Skip to main content

C# Tutorial - The Readonly Keyword [Beginner]


C# has a ton of keywords, and it is sometimes hard to keep track of them all. One keyword that often gets lost in the shuffle is the readonly keyword, often because many people just group it with the const keyword and leave it at that. Well, the readonly keyword deserves better than that - and so here today we are going to talk about what exactly it does, how it differs from const, and why you would ever want to use it at all.

The readonly keyword does exactly what its name states - it makes a field read only. Well, I guess it doesn't quite mean just that - because there is one point in the lifespan of an object that a readonly field can be set. That point is during object initialization. And this fact right here is why readonly differs from const - a const field gets determined at compile time, while a readonly field is determined at runtime. For example:
public class MyClass
{
  public const string foo = "foo";

  public MyClass()
  {
    foo = "bar";
  }
}

//Error: The left-hand side of an assignment must be a variable, property or indexer

Here we have foo which is a constant. We can only set it in its declaration, anywhere else (including the constructor, as we see here) will result in a compile error. But with the readonly keyword, the above code compiles just fine:
public class MyClass
{
  public readonly string foo = "foo";

  public MyClass()
  {
    foo = "bar";
  }
}
 
This compiles because it is legal to set a readonly field at any point during the initialization of an object - both up in the field declaration and in the constructor. This means that we can actually dynamically determine the value of a readonly field at runtime by passing it in the constructor, or perhaps calculating it in the constructor:
public class MyClass
{
  public readonly string foo = "foo";

  public MyClass(string abc)
  {
    foo = abc;
  }
}
 
But if we try and set a readonly field at any other point, we get a compile error:
public class MyClass
{
  public readonly string foo = "foo";

  public MyClass(string abc)
  {
    foo = abc;
  }

  public void SetFoo(string newFoo)
  {
    foo = newFoo;
  }
}

//Error: A readonly field cannot be assigned to (except in a constructor or a variable initializer)

One somewhat surprising case at first (but not so surprising after you think about it a bit) where we cannot set a readonly has to do with inheritance. For example:
public class MyClass
{
  public readonly string foo = "foo";

  public MyClass(string abc)
  {
    foo = abc;
  }
}

public class MyExtClass : MyClass
{
  public MyExtClass(string abc1, string abc2)
    : base(abc1)
  { foo = abc2; }
}

//Error: A readonly field cannot be assigned to (except in a constructor or a variable initializer)

You cannot set a readonly belonging to a base class in the constructor for the current class. This makes sense after a moment of thought - the base class is already initialized (its constructor has already been run) and so letting a readonly field be modified here undermines what the readonly keyword is supposed to be accomplishing.

Ok, so now that we know what the readonly keyword is and what it does, why should we use it? There are a number of reasons, and they all have to do with code that is easier to read and think about. Sadly, there are no performance benefits to using the readonly keyword - none that I can find, anyway. This is somewhat perplexing - one would think there would be some performance benefits from using immutable variables- perhaps one of our readers will be able to tell me differently.

But anyway, back to the reasons you should use the readonly keyword. For instance, take the following code:
public class MyClass
{
  private string _foo = "foo";

  public MyClass(string foo)
  {
    _foo = foo;
  }

  public string Foo
  { 
    get { return _foo; } 
  }
}
 
There is nothing actually wrong with this code - we have a private string _foo and we expose it as a property Foo, only creating a getter. This essentially exposes a read only version of _foo. But if _foo isn't going to be changing internal to the class either, it is much nicer to write the code this way:
public class MyClass
{
  public readonly string foo = "foo";

  public MyClass(string foo)
  {
    foo = foo;
  }
}
 
Here, we lose the property altogether, and instead just have a public read only field. Another reason to use the readonly keyword is that objects that are immutable are much easier to reason about. For example, here we have two objects, a three dimensional point object, and an element that needs to store its own position and notify others of changes:
public class Vector3
{
  public event EventHandler ValueChanged;
  private float _x;
  private float _y;
  private float _z;

  public Vector3(float x, float y, float z)
  {
    _x = x;
    _y = y;
    _z = z;
  }

  private void OnValueChanged()
  {
    if (ValueChanged != null)
      ValueChanged(this, EventArgs.Empty);
  }

  public float X
  {
    get
    {
      return _x;
    }
    set
    {
      if (_x == value)
        return;

      _x = value;
      OnValueChanged();
    }
  }

  public float Y
  {
    get
    {
      return _y;
    }
    set
    {
      if (_y == value)
        return;

      _y = value;
      OnValueChanged();
    }
  }

  public float Z
  {
    get
    {
      return _z;
    }
    set
    {
      if (_z == value)
        return;

      _z = value;
      OnValueChanged();
    }
  }
}

public class Element
{
  public event EventHandler PositionChanged;
  private Vector3 _position = null;

  public Element(Vector3 pos)
  {
    Position = pos;
  }

  private void OnPositionChanged()
  {
    if (PositionChanged != null)
      PositionChanged(this, EventArgs.Empty);
  }

  void Position_ValueChanged(object sender, EventArgs e)
  {
    OnPositionChanged();
  }

  public Vector3 Position
  {
    get { return _position; }
    set
    {
      if (_position == value)
        return;

      if (_position != null)
        _position.ValueChanged -= new EventHandler(Position_ValueChanged);

      _position = value;
      OnPositionChanged();

      if (_position != null)
        _position.ValueChanged += new EventHandler(Position_ValueChanged);
    }
  }
}
 
That's a bunch of code! Mostly because we have to keep checking values and triggering events, so that we make sure that the final PositionChanged event always gets fired if anything about the position changes. Plus we have to worry about someone holding on to our Vector3 object for this element and passing it along, and passing it along, until it reaches the hands of someone who shouldn't be able to modify our position at all.

So lets take a look at how this code looks with the use of the readonly keyword, making the Vector3 object immutable:
public class Vector3
{
  public readonly float X;
  public readonly float Y;
  public readonly float Z;

  public Vector3(float x, float y, float z)
  {
    X = x;
    Y = y;
    Z = z;
  }
}

public class Element
{
  public event EventHandler PositionChanged;
  private Vector3 _position = null;

  public Element(Vector3 pos)
  {
    Position = pos;
  }

  private void OnPositionChanged()
  {
    if (PositionChanged != null)
      PositionChanged(this, EventArgs.Empty);
  }

  public Vector3 Position
  {
    get { return _position; }
    set
    {
      if (_position == value)
        return;

      _position = value;
      OnPositionChanged();
    }
  }
}
 
Wow, that's a lot less code! With this new code, we no longer need the event stuff all over the Vector3 object. Plus, we don't have to worry about who is holding on to the object that contains an element's position - because they won't actually be able to modify it. To give an element a new position now, you actually need to hand it a new Vector3 object.

Well, I hope you've enjoyed this discussion about the readonly keyword.

Comments

Popular posts from this blog

C# Snippet - Shuffling a Dictionary [Beginner]

Randomizing something can be a daunting task, especially with all the algorithms out there. However, sometimes you just need to shuffle things up, in a simple, yet effective manner. Today we are going to take a quick look at an easy and simple way to randomize a dictionary, which is most likely something that you may be using in a complex application. The tricky thing about ordering dictionaries is that...well they are not ordered to begin with. Typically they are a chaotic collection of key/value pairs. There is no first element or last element, just elements. This is why it is a little tricky to randomize them. Before we get started, we need to build a quick dictionary. For this tutorial, we will be doing an extremely simple string/int dictionary, but rest assured the steps we take can be used for any kind of dictionary you can come up with, no matter what object types you use. Dictionary < String , int > origin = new Dictionary < string , int >(); ...

C# WPF Printing Part 2 - Pagination [Intermediate]

About two weeks ago, we had a tutorial here at SOTC on the basics of printing in WPF . It covered the standard stuff, like popping the print dialog, and what you needed to do to print visuals (both created in XAML and on the fly). But really, that's barely scratching the surface - any decent printing system in pretty much any application needs to be able to do a lot more than that. So today, we are going to take one more baby step forward into the world of printing - we are going to take a look at pagination. The main class that we will need to do pagination is the DocumentPaginator . I mentioned this class very briefly in the previous tutorial, but only in the context of the printing methods on PrintDialog , PrintVisual (which we focused on last time) and PrintDocument (which we will be focusing on today). This PrintDocument function takes a DocumentPaginator to print - and this is why we need to create one. Unfortunately, making a DocumentPaginator is not as easy as...

C# WPF Tutorial - Implementing IScrollInfo [Advanced]

The ScrollViewer in WPF is pretty handy (and quite flexible) - especially when compared to what you had to work with in WinForms ( ScrollableControl ). 98% of the time, I can make the ScrollViewer do what I need it to for the given situation. Those other 2 percent, though, can get kind of hairy. Fortunately, WPF provides the IScrollInfo interface - which is what we will be talking about today. So what is IScrollInfo ? Well, it is a way to take over the logic behind scrolling, while still maintaining the look and feel of the standard ScrollViewer . Now, first off, why in the world would we want to do that? To answer that question, I'm going to take a an example from a tutorial that is over a year old now - Creating a Custom Panel Control . In that tutorial, we created our own custom WPF panel (that animated!). One of the issues with that panel though (and the WPF WrapPanel in general) is that you have to disable the horizontal scrollbar if you put the panel in a ScrollV...