#790 – Property get and set Accessors Can Have Different Access Modifiers

When you implement a property in a class, you can specify different access modifiers for the get vs. set accessors.  This is true whether you are implementing the property yourself, or using an automatic property.

Different combinations of access modifiers include:

  • get/set both public – client can read/write property value
  • get/set both private – client has no access to the property
  • get public, set private – property is read-only
  • get private, set public – property is write-only
        // get/set both public
        public string Name { get; set; }

        // get/set both private
        private string SecretName { get; set; }

        // public get => read-only
        public string CalcName { get; private set; }

        // public set => write-only
        public string WriteOnlyName { private get; set; }

#788 – A Backing Field Stores Data for a Property

When you create a property, you’re creating a set of accessor methods to read and write the property’s value.  You also typically need a place to store the actual property value.

The data member where the property’s value is actually stored is known as a backing field, typically defined as a private field.

When you create an auto-implemented property, you don’t explicitly declare a backing field, but the compiler creates one for you in the IL that is generated.  Your code doesn’t have access to the field.

        // Backing field not declared, created automatically
        public int Age { get; set; }

If you create the property explicitly, then you’ll declare the backing field yourself.

        // Backing field
        private int age;

        // Property
        public int Age
        {
            get { return age; }
            set
            {
                if (value != age)
                    age = value;
            }
        }

#702 – An Automatic Property Must Define Both get and set Accessors

When you define an automatic property, you must include both get and set accessors.

        public string Name { get; set; }

It wouldn’t make sense to omit either accessor, since they are the only mechanism for reading from or writing to the property.

Although you can’t strictly create a read-only or write-only automatic property, you can use access modifiers so that the property is effectively read-only or write-only, from outside the class.

        // Automatic property that is read-only from outside class
        public string Temperament { get; protected set; }

        // Automatic property that is write-only from outside class
        public string Password { protected get; set; }

#701 – Centralize Business Rules Logic in set Accessors

You can use a property’s set accessor to enforce business rules for that property, e.g. min/max values for the property.

If you have a constructor that accepts initial values for some properties of a class, or methods that accept values, you can avoid checking constraints on these parameters by delegating the enforcement of the rules to the set accessor.

For example:

    public class Dog
    {
        // Public properties
        public string Name { get; set; }

        private int age;
        public int Age
        {
            get { return age; }

            // Set accessor checks for valid Age values
            set
            {
                if (value != age)
                {
                    if ((value > 0) && (value < 30))
                        age = value;
                    else
                        throw new Exception("Age is out of range");
                }
            }
        }

        // Constructor
        public Dog(string name, int age)
        {
            Name = name;

            // Don't validate age value here, but let set accessor do it
            Age = age;
        }
    }

#700 – Using a set Accessor To Enforce Casing

A set accessor allows client code to give a property a new value.  You typically use the set accessor to do any required validation or conversion of the input value.  This is the point where you impose any business rules related to the value of the property being set.

For example, you might enforce a requirement that a particular string-based property always be uppercase.  Instead of throwing an exception if some calling code tries to set a property that is not uppercase, you can just automatically convert all values to uppercase.

    public class Car
    {
        private string licPlate;
        public string LicPlate
        {
            get { return licPlate; }
            set
            {
                if (value != licPlate)
                {
                    if (value.Length != 7)
                        throw new Exception("Invalid license plate number");
                    else
                        licPlate = value.ToUpper();
                }
            }
        }

    }

 

            Car c = new Car();
            c.LicPlate = "vpn 123";

            Console.WriteLine(c.LicPlate);

#610 – Lazy Evaluation in Property Get Accessors

One of the benefits in using a property in a class, rather than a public field, is that you can delay calculation of the property’s value until client code actually tries to read the value.

In the code below, we define a FullDogDescription property that is read-only.  The private backing variable is initialized to an empty string and we only calculate its value in the get accessor when someone tries to read the property’s value.

<pre>        private string fullDogDescription = "";
        public string FullDogDescription
        {
            get
            {
                // Generate full description the first time that
                // someone reads this property.
                if (fullDogDescription == "")
                    fullDogDescription = GenerateDogDescription();

                return fullDogDescription;
            }
        }

The benefit of doing this is that if the call to GenerateDogDescription takes some time, we don’t spend the time calculating a value until some piece of code actually needs a value.

#361 – An Abstract Property Has No Implementation

You can declare a property as abstract, indicating that it has no implementation in the base class.  The base class indicates the property’s type and whether it has get and set accessors in any derived classes.

A base class that defines an abstract property must also be marked as abstract itself.  It wouldn’t make sense to create instances of the base class, since the implementation for the abstract property is missing.

A derived class must provide the implementation (in get/set accessors) for any properties that are abstract in the base class.

Defining an abstract property:

    public abstract class Dog
    {
        public abstract string Temperament { get; }
    }

Providing an implementation for the get accessor in a derived class:

    public class Terrier : Dog
    {
        protected string temperament;
        public override string Temperament
        {
            get
            {
                return string.Format("Terrier {0} is {1}", Name, temperament);
            }
        }

#360 – Property Modifiers Required for Polymorphic Behavior

There are three combinations of modifiers that make sense, in determining whether properties in a class are virtual or non-virtual.

Typical combinations of modifiers for base class / derived class (assuming that the property’s name and type are the same in both the base and derived class):

  • (no modifier) / new – Both properties are non-virtual, derived class property hides the base class property
  • virtual / override – Both properties are virtual and support polymorphic behavior
  • virtual / new – Base class property is virtual, derived class property is non-virtual, derived class property hides the base class property

There are two other combinations that are allowed, but result in a compiler warning indicating that you should use new in the derived class to be explicit:

  • (no modifier) / (no modifier) – is equivalent to: (no modifier) / new
  • virtual / (no modifier) – is equivalent to: virtual / new

#359 – The Difference Between Virtual and Non-Virtual Properties

In C#, virtual properties support polymorphism, by using a combination of the virtual and override keywords.  With the virtual keyword on the property in the base class and the override keyword on the property in the derived class, both properties are said to be virtual.

Properties that don’t have either the virtual or override keywords, or that have the new keyword, are said to be non-virtual.

When you read or write a virtual property through an object reference, the run-time type of the object is used to determine which implementation of the property to use.

When you read or write a non-virtual property through an object reference, the compile-time type of the object is used to determine which implementation of the property to use.

#358 – Virtual Properties Support Polymorphism

In C#, polymorphism is implemented using virtual members–which can be methods, properties, indexers or events.

A virtual property has an implementation in the base class that can be overridden in a derived class.  When the property is read or written, the get or set accessor that is used is determined at run-time based on the type of the underlying object.

A virtual property is defined in the base class using the virtual keyword.

        protected string temperament;
        public virtual string Temperament
        {
            get
            {
                return string.Format("{0} is {1}", Name, temperament);
            }
        }

A virtual property is overridden in a derived class using the override keyword.

        public override string Temperament
        {
            get
            {
                return string.Format("Terrier {0} is {1}", Name, temperament);
            }
        }

Using the property:

            Dog kirby = new Dog("Kirby", 15);
            Console.WriteLine(kirby.Temperament);  // Kirby is Average

            Dog jack = new Terrier("Jack", 15);
            Console.WriteLine(jack.Temperament);   // Terrier Jack is Surly