Storing data with fields

Next, we will define some fields in the class to store information about a person.

Defining fields

Inside the Person class, write the following code. At this point, we have decided that a person is composed of a name and a date of birth. We have encapsulated these two values inside the person. We have also made the fields public so that they are visible outside the class itself:

    public class Person : object 
    { 
      // fields 
      public string Name; 
      public DateTime DateOfBirth; 
    } 

Note

You can use any type for a field, including arrays and collections, for example, if you need to store multiple values.

In Visual Studio 2017, you might want to click, hold, and drag the tabs for one of your open files to arrange them so that you can see both Person.cs and Program.cs at the same time, as shown in the following screenshot:

Defining fields

In Visual Studio Code, you can click on the Split Editor button or press Cmd + and then close one copy of the duplicated file editor so that you have two files open side by side, as shown in the following screenshot:

Defining fields

Understanding access modifiers

Note that, like we did with the class, we applied the public keyword to these fields. If we hadn't, then they would be private to the class, which means they are accessible only inside the class.

There are four access modifier keywords that you can apply to a class member, such as a field or method. Part of encapsulation is choosing how visible the members are:

Access Modifier

Description

private

Member is accessible inside the type only. This is the default.

internal

Member is accessible inside the type and any type in the same assembly.

protected

Member is accessible inside the type and any type that inherits from the type.

internal protected

Member is accessible inside the type, any type in the same assembly, and any type that inherits from the type.

public

Member is accessible everywhere.

Tip

Good Practice

Explicitly apply one of the access modifiers to all type members even if you want to use the default, which is private.

Inside the Main method, change the code to look like this:

    var p1 = new Person(); 
    p1.Name = "Bob Smith"; 
    p1.DateOfBirth = new DateTime(1965, 12, 22); 
    WriteLine($"{p1.Name} was born on {p1.DateOfBirth:dddd, d MMMM  yyyy}");

Run the application and view the output:

Bob Smith was born on Wednesday, 22 December 1965

You can also initialize fields using a short-hand object initializer syntax using curly braces.

Add the following code underneath the existing code to create another new person. Notice the different format code for the date of birth when writing to the console:

    var p2 = new Person { Name = "Alice Jones", DateOfBirth = new  
    DateTime(1998, 3, 17) }; 
    WriteLine($"{p2.Name} was born on {p2.DateOfBirth:d MMM yy}"); 

Run the application and view the output:

Bob Smith was born on Wednesday, 22 December 1965
Alice Jones was born on 17 Mar 98

Storing a value using the enum keyword

Sometimes, a value needs to be one of a limited list of options. For example, a person may have a favorite ancient world wonder. Sometimes, a value needs to be combination of a limited list of options. For example, a person may have a bucket list of ancient world wonders they want to visit. We can store this data using an enum type.

An enum is a very efficient way of storing one or more choices because, internally, it uses int values in combination with a lookup table of string descriptions.

In Visual Studio 2017, add a new class to the Ch06_PacktLibrary project named WondersOfTheAncientWorld by pressing Shift + Alt + C or going to Project | Add Class....

In Visual Studio Code, add a new class to the project by selecting Ch06_PacktLibrary, clicking the New File button in the mini toolbar, and entering the name WondersOfTheAncientWorld.cs, as shown in the following screenshot:

Storing a value using the enum keyword

Modify the WondersOfTheAncientWorld.cs class file to make it look like this:

    namespace Packt.CS7 
    { 
      public enum WondersOfTheAncientWorld 
      { 
        GreatPyramidOfGiza, 
        HangingGardensOfBabylon, 
        StatueOfZeusAtOlympia, 
        TempleOfArtemisAtEphesus, 
        MausoleumAtHalicarnassus, 
        ColossusOfRhodes, 
        LighthouseOfAlexandria 
      } 
    } 

In the Person class, add the following statement to your list of fields:

    public WondersOfTheAncientWorld FavouriteAncientWonder; 

Back in the Main method of Program.cs, add the following statements:

    p1.FavouriteAncientWonder =
      WondersOfTheAncientWorld.StatueOfZeusAtOlympia; 
    WriteLine($"{p1.Name}'s favourite wonder is
    {p1.FavouriteAncientWonder}"); 

Run the application and view the additional output:

Bob Smith's favourite wonder is StatueOfZeusAtOlympia

For the bucket list, we could create a collection of instances of the enum, but there is a better way. We can combine multiple choices into a single value using flags.

Modify the enum to look as shown in the following code. Note that I have used the left shift operator (<<) to set individual bits within the flag. I could also have set the values to 1, 2, 4, 8, 16, 32, and so on:

    namespace Packt.CS7 
    { 
      [System.Flags] 
      public enum WondersOfTheAncientWorld : byte 
      { 
        None = 0, 
        GreatPyramidOfGiza = 1, 
        HangingGardensOfBabylon = 1 << 1, 
        StatueOfZeusAtOlympia = 1 << 2, 
        TempleOfArtemisAtEphesus = 1 << 3, 
        MausoleumAtHalicarnassus = 1 << 4, 
        ColossusOfRhodes = 1 << 5, 
        LighthouseOfAlexandria = 1 << 6 
      } 
    } 

Note

We are assigning explicit values for each choice that would not overlap when looking at the bits stored in memory. We must also mark the enum with the System.Flags attribute. Normally, an enum uses an int variable internally, but since we don't need values that big, we can make it more efficient by telling it to use a byte variable.

If we want to indicate that our bucket list includes the Hanging Gardens and the Mausoleum at Halicarnassus, then we would want the 16 and 2 bits set to 1. In other words, we would store the value 18:

64

32

16

8

4

2

1

0

0

0

1

0

0

1

0

0

In the Person class, add the following statement to your list of fields:

    public WondersOfTheAncientWorld BucketList; 

Back in the Main method of Ch06_PeopleApp, add the following statements to set the bucket list using the | operator (logical OR) to combine enum values. We could also set the value using the number 18 cast into the enum type as in the comment:

    p1.BucketList = WondersOfTheAncientWorld.HangingGardensOfBabylon |      
    WondersOfTheAncientWorld.MausoleumAtHalicarnassus; 
    // p1.BucketList = (WondersOfTheAncientWorld)18; 
    WriteLine($"{p1.Name}'s bucket list is {p1.BucketList}"); 

Run the application and view the additional output:

Bob Smith's bucket list is HangingGardensOfBabylon,
MausoleumAtHalicarnassus

Tip

Good Practice

Use enum values to store combinations of discreet options. Derive an enum from byte if there are up to eight options, from short if there are up to 16 options, from int if there are up to 32 options, and from long if there are up to 64 options.

Storing multiple values using collections

Let's add a field to store a person's children. This is an example of aggregation because children are instances of a class that is related to the current person, but are not part of the person itself.

We will use a generic List<T> collection type, so we need to import the System.Collections.Generic namespace:

    using System.Collections.Generic; 

Then we can declare a new field in the Person class:

    public List<Person> Children = new List<Person>(); 

Notice that we need to ensure the collection is initialized to a new instance of a collection before we can add items to the collection.

In the Main method, add the following code:

    p1.Children.Add(new Person()); 
    p1.Children.Add(new Person()); 
    WriteLine($"{p1.Name} has {p1.Children.Count} children."); 

Run the application and view the output:

Bob Smith has 2 children.

Making a field static

The fields that we have created so far have all been instance members, meaning that a copy of each field exists for each instance of the class that is created.

Sometimes, you want to define a field that only has one copy that is shared across all instances. These are called static members.

In the Ch06_PacktLibrary project, add a new class named BankAccount. Modify the class as shown in the following code:

    namespace Packt.CS7 
    { 
      public class BankAccount 
      { 
        public string AccountName; 
        public decimal Balance; 
        public static decimal InterestRate; 
      } 
    } 

Note

Each instance of BankAccount will have its own AccountName and Balance, but all instances will share a single InterestRate value.

In Program.cs and its Main method, add the following code where we will set the shared interest rate and then create two instances of the BankAccount type:

    BankAccount.InterestRate = 0.012M; 
    var ba1 = new BankAccount(); 
    ba1.AccountName = "Mrs. Jones"; 
    ba1.Balance = 2400; 
    WriteLine($"{ba1.AccountName} earned {ba1.Balance *
    BankAccount.InterestRate:C} interest."); 
    var ba2 = new BankAccount(); 
    ba2.AccountName = "Ms. Gerrier"; 
    ba2.Balance = 98; 
    WriteLine($"{ba2.AccountName} earned {ba2.Balance *
    BankAccount.InterestRate:C} interest."); 

Run the application and view the additional output:

Mrs. Jones earned £28.80 interest.
Ms. Gerrier earned £1.18 interest.

Note

:C is a format code that tells .NET to use the currency format for the numbers. In Chapter 4, Using .NET Standard Types, you learned how to control the culture that determines the currency symbol.

Making a field constant

If the value of a field will never ever change, you can use the const keyword and assign the value at compile time.

Inside the Person class, add the following code:

    // constants 
    public const string Species = "Homo Sapien"; 

Inside the Main method, change the code to look like this. Note that, to read a constant field, you must write the name of the class, not the name of an instance of the class:

    WriteLine($"{p1.Name} is a {Person.Species}"); 

Run the application and view the additional output:

Bob Smith is a Homo Sapien

Examples of const fields in Microsoft types include System.Int32.MaxValue and System.Math.PI because neither value will ever change, as you can see in the following screenshot:

Making a field constant

Note

Good Practice

Constants should be avoided for two important reasons:

The value must be known at compile time, and it must be expressible as a literal string, Boolean, or number value.

Every reference to the const field is replaced with the literal value at compile time, which will, therefore, not be reflected if the value changes in a future version.

Making a field read-only

A better choice for fields that should not change is to mark them as read-only.

Inside the Person class, write the following code:

    // read-only fields 
    public readonly string HomePlanet = "Earth"; 

Inside the Main method, add the following code statement. Notice that, to get a read-only field, you must write the name of an instance of the class, not the type name, unlike const:

    WriteLine($"{p1.Name} was born on {p1.HomePlanet}"); 

Run the application and view the output:

Bob Smith was born on Earth

Tip

Good Practice

Use read-only fields over const fields for two important reasons:

The value can be calculated or loaded at runtime and can be expressed using any executable statement. So, a read-only field can be set using a constructor.

Every reference to the field is a live reference, so any future changes will be correctly reflected by calling code.

Initializing fields with constructors

Fields often need to be initialized at runtime. You do this in a constructor that will be called when you make an instance of the class using the new keyword. Constructors execute before any fields are set by the code that is using the type.

Inside the Person class, add the following highlighted code after the existing read-only HomePlanet field:

    // read-only fields 
    public readonly string HomePlanet = "Earth"; 
    public readonly DateTime Instantiated;
// constructors 
    public Person() 
    { 
      // set default values for fields 
      // including read-only fields 
      Name = "Unknown"; 
      Instantiated = DateTime.Now; 
    } 

Inside the Main method, add the following code:

    var p3 = new Person(); 
    WriteLine($"{p3.Name} was instantiated at  {p3.Instantiated:hh:mm:ss} on     
    {p3.Instantiated:dddd, d MMMM  yyyy}"); 

Run the application and view the output:

Unknown was instantiated at 11:58:12 on Sunday, 12 March 2017

You can have multiple constructors in a type.

Inside the Person class, add the following code:

    public Person(string initialName) 
    { 
      Name = initialName; 
      Instantiated = DateTime.Now; 
    } 

Inside the Main method, add the following code:

    var p4 = new Person("Aziz"); 
    WriteLine($"{p4.Name} was instantiated at
    {p4.Instantiated:hh:mm:ss} on {p4.Instantiated:dddd, d MMMM
    yyyy}"); 

Run the application and view the output:

Aziz was instantiated at 11:59:25 on Sunday, 4 June 2017

Constructors are a special category of method. Let's look at methods in more detail.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.100.20