CrimsonX
CrimsonX

Reputation: 9238

How can I ensure this private readonly array is actually private and readonly?

I'm trying to figure out how I am able to successfully change a "readonly" array. The code below runs successfully, but I'm quite confused as to why the dereferencing of a private/readonly array is legal, as marked below:

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      MyClass myClass = new MyClass();
      myClass.Time[5] = 5; // Why is this legal? How can I make it illegal?
    }
  }

  public class MyClass
  {
    private readonly uint[] time;
    public IList<uint> Time
    {
      get { return time; }
    }

    public MyClass()
    {
      time = new uint[7];
    }
  }
}

As I Note above, I would expect that Time[5] would be illegal due to the fact that public IList Time does not have a setter.

How can I change MyClass to ensure that it is not legal to do myClass.Time[5] ?

Note: I've clarified the intent of this question, I was unclear at the start that the intention is to make this ILLEGAL. And I want to understand why its legal in the first place as is.

Upvotes: 1

Views: 1054

Answers (3)

Waleed Al-Balooshi
Waleed Al-Balooshi

Reputation: 6406

As I Note above, I would expect that Time[5] would be illegal due to the fact that public IList Time does not have a setter.

The absence of a setter means that you can't assign a NEW ARRAY to the backing field of the property, but it doesn't mean that you can't change the CURRENT array reference that the backing field is pointing to.

Additionally, how can I create an array in the constructor which is read-only and unchangeable outside of this class?

You can instatnitate a readonly field either at the declaration stage or in the constructor of the class as per MSDN.

As for how to fix this, the following MSDN article discuses this exact issue and some way to remedy it. I am not sure what your requirements are, but I would recommend looking into implementing a custom collection using ReadOnlyCollectionBase then passing that along or you can use ReadOnlyCollection<T>. The link to the ReadOnlyCollectionBase provides an example of an implementation.

Upvotes: 5

Jacob Krall
Jacob Krall

Reputation: 28825

readonly means that the field itself cannot be changed (that is, you cannot say "this.time = new uint[10]" outside the constructor). Arrays are mutable objects, so anywhere you have a reference to the array, the possessor of that reference can change the values stored in that array.

readonly fields are writable only in the constructor (this includes field initializers)

Two options for you:

  • Do a shallow copy of the array in the Time property, so callers can't modify your copy of the array
  • Use ReadOnlyCollection to prevent modifications at all

Upvotes: 2

petro.sidlovskyy
petro.sidlovskyy

Reputation: 5093

Time property hasn't setter so you will be not able to do something like this:

static void Main(string[] args)
{
  MyClass myClass = new MyClass();
  myClass.Time = new List<uint>();
}

but you are able to use indexer so Time[5] is legal.

Additionally, how can I create an array in the constructor which is read-only and unchangeable outside of this class?

read-only fields can be initialized in constructor only. Initialization right after declaration is the same as initialization in constructor.

Upvotes: 0

Related Questions