best practice

Read-Only Public Properties / State in C#

There are a few ways you may choose to implement a read-only property in C#. Some options are better than others, but how do you know which is the best? Let’s take a look at what you could potentially use and what the pros/cons are:

Naive approach

public class Reader
{
    private string _filename = "Inputfile.txt";

    public string Filename { get { return _filename; } }
}

At first glance, the code above should be ideal. It gives you an explicitly read-only property and correctly hides the internal backing variable. So, what’s wrong?

Internal variable is visible, as well as the property

This makes the code a little more brittle to changes. In the implementation for Reader, developers could use either _filename or the property Filename. If in the future, the code was amended to make the Filename property virtual, all usages of _filename would be immediate bugs. You always want the code to be as resilient as possible. Of course, you should always use the property in code, but mistakes are very easy to make and overlook. It’s much better to make it impossible to write incorrect code – ensuring you end up in the pit of success.

_filename is mutable!

While the property itself is read-only, the backing variable is mutable! Our implementation of Reader is free to change the property as much as it likes. This might be desirable, but generally, we want the state to be as fixed as possible.

Better approach, but not ideal

public class Reader
{
    private const string _filename = "Inputfile.txt";

    public string Filename => _filename;
}

The property accessor is now more concise, and the backing store is read-only. This is good, but it could be better.

Use of const is risky

What? const is risky? In this case, it could be. Const works by substituting all uses of the variable with the explicit value directly into the bytecode at compilation time. This means const is super-fast because there’s no memory usage and no memory access. The drawback is if the const value is changed, but an assembly referencing this assembly isn’t re-compiled. If this happens the other assembly will still see the ‘old’ value. In this example, this could happen if another assembly extended the Reader class it wouldn’t see changes to the private const variable unless it was also re-compiled. To make it even more confusing – it would likely ‘see’ the changes with Debug builds, but not with Release builds. The simple fix to this const difficulty is to use readonly instead of const for values that could change, such as settings. Genuine constants, such as PI, should remain as const.

Better again, but still not ideal

public class Reader
{
    private static readonly string _filename = "Inputfile.txt";

    public string Filename => _filename;
}

The code is getting a little more reliable here. The filename state variable is now static readonly so it’s memory usage is low, while still offering flexibility to changes – even if consuming assemblies aren’t recompiled with every change we make to our assembly.

As an aside, read-only state variables should be static wherever possible. If the variable isn’t static, it’ll be created and initialised with every single instance of the class – rather than just once across all instances.

Ideal approach

public class Reader
{
    public string Filename { get; } = "Inputfile.txt";
}

This is the best solution possible because it gives us maximum flexibility, with the minimum amount of potential issues going forward.

Good Locality

The initialisation happens with the property declaration ensuring high code locality. Before the property could be in a completely different area of the code file to the actual implementation of the private backing state.

No access to backing variable / state

The backing variable is now hidden from us, so we can’t accidentally use it instead of the property. If we make the property virtual, we can’t accidentally use the backing variable by mistake elsewhere in the code.

Easy to change to constructor initialisation

We can just remove the initialiser and put initialisation into the constructor. The property is still read-only, and the backing variable is still invisible. Easy!

Posted by Dan in C#, Programming, 0 comments

Encapsulation

It’s been a while since I’ve written anything, mostly because almost any ‘how to’ has already been written. So let’s start looking into the more difficult realm of architecture of the application rather than how to do this or that.

Encapsulation is one of the basic tenants of Object Oriented programming, and is often over-looked. In short encapsulation means hiding the internal functionality away from the consumer of your class. But what does that actually mean?

It means you’ve got some difficult decisions to make with each class you build! To make my point I’m going to use a class that accesses a database. In this class we’re going to save people, think of it like a contacts list. This ‘PeopleList’ is going to save people, and then later fetch people from a database. A naive approach might have the following methods:

  • InsertPerson
  • UpdatePerson
  • DeletePerson
  • GetPerson
  • GetPeople

Where has the encapsulation been lost? It’s been lost with the Insert/Update methods, both of which are shouting that you’re using a SQL database and you’re exposing the underlying requirements of the DB to the user of your class. The users of your class doesn’t care about the database you use, just that they want to persist people and then fetch them. Differentiating between inserts and updates is not relevant to the users of the class, and just adds additional work for them.

This is one of the most important things you must do each time you design a class – consider what does the user of the class want to do? You then make that task as easy as possible. You only write the class once, but this class might be used many thousands of times over many years. A better approach would be to have the following methods instead:

  • SavePerson
  • DeletePerson
  • GetPerson
  • GetPeople

Now your class is much simpler to use. Does the user have to consider if they have already saved the person anymore? No, now all they need to do is throw a person at your class and you worry about the details. You’ve encapsulated the functionality so that the user doesn’t have to worry about logic you should be worrying about.

The great thing about doing this, is the underlying data store of this class can now be changed without any changes to the public interface of the class. We could use web service instead, and you’re still handling the logic yourself. If the web services are well designed you’ve effectively reduced the query count by one since the user of your class won’t have to check if the person exists already or not. Not only is it easier to use your new class, but it’s faster too!

Coming soon: Encapsulation Part 2!

Posted by Dan in Guides, Programming, 0 comments