Search code examples
c#propertiesreadonly

Restricting access to method calls on read-only properties


I have a class that defines a read-only property that effectively exposes a private field, something like this:

public class Container
{
    private List<int> _myList;

    public List<int> MyList
    {
        get { return _myList;}
    }

    public Container() : base ()
    {
        _myList = new List<int>();
    }

    // some method that need to access _myList
    public SomeMethod(int x)
    {
         _myList.Add(x);
    }
}

now it's impossible for the consumer to manage my property directly, so code like aContainer.MyList = new List(); generates a compile-time error. However, the consumer is absolutely free to call all sorts of methods on the reference he got, so this is perfectly valid code

Container c = new Container();  
Console.WriteLine(c.MyList.Count);  
c.MyList.Add(4);  
Console.WriteLine(c.MyList.Count);  

which kind of defeats the whole read-only concept.

Is there any sane workaround that would enable me to have a real read-only reference propery?

P.S. I cannot just return a copy of the list because then the user will think that he made all the changes necessary, but alas... they will be gone.


Solution

  • The reference is "readonly", the the actual object. I.e. you can't replace the reference with another object. So if you have a class that breaks it like this:

    public class Container
    {
        private readonly  List<int> _myList;
    
        public List<int> MyList
        {
            get { return _myList;}
        }
    
        public Container() : base ()
        {
            _myList = new List<int>();
        }
    
        public void BreakReadOnly()
        {
            _myList = new List<int>();
        }
    }
    

    …then it won't even compile. It's because a readonly field can't be reassigned with any other object. In this case BreakReadOnly will try to assign a new list.

    If you really want a readonly collection of it then you can do it like this:

        public ReadOnlyCollection<int> MyList
        {
            get { return _myList.AsReadOnly(); }
        }
    

    Hope this helps.

    Updated: Removed use of IEnumerable.