#256 – Using Static Fields

Let’s say that we have both instance and static fields defined in a class:

        public string Name;

        public static string Creed;

This allows us read and write the Name property for each instance of the Dog class that we create.

            Dog kirby = new Dog();
            kirby.Name = "Kirby";

            Dog jack = new Dog();
            jack.Name = "Jack";

Notice that each instance of a Dog has its own copy of the Name field, since Name is an instance field.

We can also read/write the static Creed field, using the class name to qualify the field, rather than an instance variable.

            Dog.Creed = "Man's best friend";

There is only one copy of the Creed field, since Creed is a static field.

Advertisements

#255 – Static Fields vs. Instance Fields

When you declare a field in a class using the syntax below, you get an instance field, meaning that you’ll get one copy of the field’s data for each instance of the class that is created.  The field’s data is stored in the object (an instance of the class).

    public class Dog
    {
        public string Name;    // Instance field
    }

You can also define static fields in a class.  A static field is a variable where we can store a piece of data for the entire class, rather than a piece of data for each instance of the class.

You declare a static field using the static keyword.

    public class Dog
    {
        // Static field
        public static string Motto = "Man's best friend";
    }

With static fields, we always have exactly one copy of the field, no matter how many instances of the class we create.

#254 – Implementing a Read-Only Property with a Private Set Accessor

One way to implement a read-only property is to provide only a get accessor, letting the code internal to the class write the property’s value by writing directly to a private backing variable.

        private string personalHowl;
        public string PersonalHowl
        {
            get { return personalHowl; }
        }

However, it still might be helpful for code in the class to have a set accessor, which serves as a single place to execute whatever code is required when writing the property’s value.

You can use the private access modifier to make the set accessor available only to code within the class.  The property will appear to be read-only from code outside of the class.

        private string personalHowl;
        public string PersonalHowl
        {
            get { return personalHowl; }

            private set { personalHowl = value.ToUpper(); }
        }

#253 – Implementing a Read-Only Automatic Property

When using the automatic property syntax,C# requires that you define both a get and a set accessor.  But with the default syntax, you end up with a read/write property.

        public int Age { get; set;  }

But what if we want a read-only property, from the client code’s perspective?  Since we’re required to define the set accessor, it looks like client code would always be able to write to the property.

The solution is that we can add a private access modifier to the set accessor.

        public int Age { get; private set; }

With the set accessor private, code external to the class can read the property’s value, but not write to it.  But code within the class can still write to the property.

#252 – Automatic Properties

The typical syntax for a property implementation in C# is to define the public interface for the property and then have the implementation of the get and set accessors for the property read/write to a private backing variable.

        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

C# provides a shortcut for this structure through the use of automatic properties.  You can avoid declaring the private backing variable and implementing the get/set accessors by simply declaring the get/set accessors without a body.

        public string Name { get; set; }

When you declare a property this way, it appears exactly the same to any client code.  The underlying code generated by the compiler is also the same–a public property with a backing variable–but you don’t actually have access to the backing variable.

#251 – Class Properties Support the Principle of Encapsulation

Encapsulation is one of the core principles of object-oriented programming.  Encapsulation is the idea of hiding implementation details of a class from the users of that class and only exposing a public interface.

Class properties in C# support the idea of encapsulation.  Client code that wants to read or write a property has access only to its public interface–the data type of the property and the knowledge that there is a get or a set accessor (or both) for that property.

Client code that reads or writes a property has no information about:

  • How the class actually stores the property data
  • The implementation of the get accessor–how data is retrieved when a client reads the property value
  • The implementation of the set accessor–how data is stored when a client writes the property value

#250 – Using a set Accessor to Convert or Validate Property Data

We can use a property’s set accessor to do some validation on the new property value.  We may want to force the data to be within a particular range, do some conversion on the data, or throw an exception if an invalid value is specified.

Here’s an example where we use the set accessor of the Dog.Age property to enforce the constraint that a dog’s age can’t be less than 0.1.

        private float age;
        public float Age
        {
            get
            {
                return age;
            }
            set
            {
                // Enforce minimum age of 0.1
                age = (value < 0.1f) ? 0.1f : value;
            }
        }

Here’s another example, where we throw an exception if the user tries to set Name to an empty string.

        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                if (value == "")
                    throw new Exception("Name can't be empty!");
                else
                    name = value;
            }
        }