Encapsulation with Property Accessor Rescoping

A better way with Property Accessor Rescoping

Overview

I have seen many questions about the correct design of a solution that needs to keep fields completely encapsulated, and control who, and what, can write to these fields. There are three key components to encapsulation.

The Field

The field is the human-readable name that corresponds to the location where the actual data is stored in memory. The field is sometimes referred to as a variable.

The Property

The property ensures the field is encapsulated and exposes the field so it can be seen by instances (or derivations) of this class. You’ll notice that the property has the same name as the field, except it starts with a capital letter. It’s not required that your property and field have the same name; however, it’s good practice to do so, and it makes your source code more legible.

The Accessor(s)

The accessors allow the field to be written to, and read from, in a controlled manner. In the code example below, the accessors simply read and write the data; however, you could run other statements here, before writing to the field; such as data validation statements. You can create a read-only field by omitting the set accessor, and a write-only field by omitting the get accessor.

public class Member
{
    // This variable is called a field.
    private string firstName;

    // This is the property.
    public string FirstName
    {
        // These are the accessors.
        get { return this.firstName; }
        set { this.firstName = value; }
    }
}

The Old Way

This solution allows you to read and write to the field via its property, and accessors, rather than accessing the field directly. It allows you to perform validation, or check the data in any other manner to ensure it’s safe before attempting to write it into memory. It allows you to control who, and what, can access the field. This ensures that no instances or derivations of this class can access that field directly (notice the field itself is private).

public class TheOldWay
{
    // Field.
    private string firstName;

    // Property.
    public string FirstName
    {
        get { return this.firstName; }
        set
        {
            // run validation (or other) statements here.
            this.firstName = value;
        }
    }

    private void Method1()
    {
        // Writing directly to the field.
        this.firstName = “Ken”
    }

    private void Method2()
    {
        // Writing to the field via its property.
        this.FirstName = “Ken”
    }
}

In this example, both Method1, and Method2, write the name “Ken” into the firstName field. However, only Method2 will guarantee that the name will be validated in some way, or that some other statements will be executed prior to saving the new name into the field.

You may not want to perform the validation directly inside the set accessor, in most cases it’s a bad design; however, look at what we can do here:

As soon as the set accessor is accessed, we mark this class as invalid. This it will prevent any critical methods from executing until the class has been validated. You can also make the property IsValidated public, so it can be called from outside this class, and executed, on the current instance, whenever it may be required.

public class SetIsValidatedBool
{
    private string firstName;

    // Tracks this objects validation status.
    private bool isValidated = false;

    public string FirstName
    {
        get { return this.firstName; }
        set
        {
            this.firstName = value;

            // The first name was changed. It may be invalid.
            IsValidated = false;
        }
    }

    // Notice even the validation flag is encapsulated.
    private bool IsValidated
    {
        get { return this.isValidated; }
        set { this.isValidated = value; }
    }

    // Constructor- When this class is created. A first name must be passed.
    public SetIsValidatedBool(string theFirstName)
    {
        // We received a new first name, most likely from a text box control.
        // Go ahead and use it.
        this.FirstName = theFirstName;
    }

    // Simple validation method. Checks to see if the first name provided
    // is less than 5 bytes.
    private bool SomeValidationMethod()
    {
        if (this.FirstName.Length < 5)
        {
            // return some error message here...
            return false;
        }
        // The first name is larger than 5 bytes. It is OK to use.
        return true;
    }

    // This can be called from an instance of this class.
    public void DoSomethingWithThisObject()
    {
        // Before we do anything make sure this object has been validated.
        if (!IsValidated)
        {
            // Throw an exception or take some other action here. This class
            // instance has not been validated yet.
        }

        // This class instance has been validated. Place code here to
        // do something with this class.
    }
}

One problem with this, is that we may be working with data other than a first name. We may want the field available for instances of this class to read, but not write. Normally, this could be done in a few different ways. I’ll show you some of the older, and in my opinion, the wrong ways, to do this first. Then I’ll show you how you can use property accessor rescoping to your advantage.

public class WriteDirectlyToField
{
    // Field.
    private string someCriticlePeiceOfReadOnlyData;

    // Read only property. Only a get accessor has been coded.
    public string SomeCriticlePeiceOfReadOnlyData
    {
        get { return this.someCriticlePeiceOfReadOnlyData; }
    }

    public void SomeMethod()
    {
        // some statements here...

        // Write directly into the field. Since we cannot write into the
        // field via its accessor.
        this.someCriticlePeiceOfReadOnlyData = “1234”
    }
}

The previous example creates a read-only property for the field. Since there is no set accessor in this property, nothing can write to the field via its property. So, we need to set the data directly into the field itself. This is a bad idea, because our data is no longer encapsulated. Even though its being set from within the class its declared in, it’s still not a good idea to write directly into that field. In the former example, doing this would not set the isValidated flag. We are setting a constant value here, so we know it should be safe. In a real-world solution, there is no telling where this data: “1234”, is going to come from. It may come from another class, a file, or even from the Internet.

Another reason this makes a very bad design is because many methods from within this class may need to write to that field, therefore, things will very quickly get out of hand, trying to track down what methods are writing to that field, and at what time.

public class SimulatedSetAccessorMethod
{
    // Field.
    private string someCriticlePeiceOfReadOnlyData;

    // Read only property.
    public string SomeCriticlePeiceOfReadOnlyData
    {
        get { return this.someCriticlePeiceOfReadOnlyData; }
    }

    private void SomeMethod()
    {
        // Some statements here...

        // Call up our simulated set accessor method, and pass the data
        // that needs to be writen into the field.
        Set_someCriticlePeiceOfReadOnlyData(“1234”);
    }

    // Simulated set accessor.
    private void Set_someCriticlePeiceOfReadOnlyData(string theData)
    {
        this.someCriticlePeiceOfReadOnlyData = theData;
        
        // If we had an IsValidated bool in this example, it could be set
        // to "true" here. It would invalidate the class.
    }
}

The previous example is a little bit better. Now the field would technically be encapsulated, and if we always write to that field via our simulated-set-accessor method, the isValidated flag will always be set for us. There are some bad points to this solution, however.

For number one, this just adds one more method to the class, helping to clutter it up. Secondly, some people would argue that this is very clear. “It’s clear that this method writes to that field, and that this is an attempt to encapsulate the data.” However, when working with real-world solutions, we will rarely only have one field per class. There is also no guarantee that this method will be kept directly underneath the read-only property, for the field, where it can be visible at a glance. Code may be added between them, or around them (as I have done in this solution), and, sooner or later, this method is 60+ lines down the class from our property for the field. Now you’re stuck trying to locate the method amongst all the other code. You will need to be scrolling up, and down, in an attempt to understand the class. Even when care is taken, things can get misplaced, and unorganized, very quickly.

A Better Way

This example is like the former example, except that it removes the need for our simulated-set-accessor method, and re-scopes the property itself. Notice, we have changed the scope of the set accessor to private:

public class TheBetterWay
{
    // Field
    private string someCriticlePeiceOfReadOnlyData;

    // Read only property.
    public string SomeCriticlePeiceOfReadOnlyData
    {
        get { return this.someCriticlePeiceOfReadOnlyData; }
                       
        private set /* RESCOPED */
        {
            this.someCriticlePeiceOfReadOnlyData = value;
                
            // If this example had an IsValidated bool it could be set
            // to "true" here. Invalidating the class.
        }
    }

    private void SomeMethod()
    {
        // Write to our field via its rescoped accessor. If you attemped to
        // write to this field via its property from an instance of this class
        // you would receive a compilation error.
        this.SomeCriticlePeiceOfReadOnlyData = “1234”;
    }
}

This is an excellent solution because it keeps all our accessors inside the field’s property, and, it’s easy to understand (if you understand scoping). You can clearly see that this property has a public scope, therefore, any instance, or derivation, of this class, will be able to read the critical data; however, since we have re-scoped the set accessor to private, only the class within witch it is declared, can write to the property. If you were to try to write to this field from an instance of this class, you would receive a compilation error. In this example, the data is always encapsulated, and the isValidated flag will always be set, when the critical data is changed.

Conclusion

There are two rules you must follow when using this type of solution:

  1. You can re-scope only one accessor per property. Therefore, if you re-scope the set accessor, you cannot re-scope the get accessor, and vice versa. One reason being, is that if you are going to re-scope both accessors, you should just re-scope the property itself, and not the accessors. It would make no sense to have a public property with two private accessors inside of it. Just re-scope the property itself, to private. If you were to re-scope both accessors with a different scope, simply place the more accessable scope at the property level, and re-scope only the remaining accessor.
  2. The second rule you must follow, is that the re-scoped accessor must be less accessible then the property’s scope itself. You cannot have a public accessor inside of a private property.

6 Comments

  1. Howdy! I just wish to offer you a big thumbs up for your excellent information you have got right here on this post. I am returning to your web site for more soon.

Leave a Reply