I've been around this design problem many times, and never found a killer solution.
I want to expose a collection that is editable in the owner class
scope, but only readable for other public scopes.
Trial 1:
public class MyClass
{
private List<object> _myList = new List<object>();
public IEnumerable<object> MyList { get { return _myList; } }
}
The problem with this is a external code can just cast it back to List
and edit, like this:
var x = ((List<object>)MyList);
Trial 2:
public class MyClass
{
private List<object> _myList = new List<object>();
public IEnumerable<object> MyList { get { return _myList.ToList(); } }
}
This way we prevent external modification, but create a unnecessary overhead of copying the List
many times.
Trial 3:
public class MyClass
{
private List<object> _myList = new List<object>();
private ReadOnlyCollection<object> _roList =
new ReadOnlyCollection<object>(_myList)
public IEnumerable<object> MyList { get { return _roList; } }
}
This is the standard solution, wich I use currently, but ReadOnlyCollection
is about 30% slower:
Debug Trace:
Use normal foreach on the ReadOnlyCollection
Speed(ms): 2520,3203125
Result: 4999999950000000
use<list>.ForEach
Speed(ms): 1446,1796875
Result: 4999999950000000
Use normal foreach on the List
Speed(ms): 1891,2421875
Result: 4999999950000000
Is there a 'perfect' way of doing this? Thanks.
UnModifiable Collection Example. Read-only List, Map and Set in Java. A read-only List means a List where you can not perform modification operations like add, remove or set.
In C# there is the readonly keyword that enforced the rule that the variable must be initialised as it's declared or in the constructor. This works as expected for simple types, but for objects and lists it's not quite like that. With a list, you can still add, remove and change items in the list.
ReadOnlyCollection makes an array or List read-only. With this type from System. Collections. ObjectModel, we provide a collection of elements that cannot be changed.
Have you tried returning the enumerator?
public class MyClass
{
private List<object> _myList = new List<object>();
public IEnumerable<object> MyList { get { yield return _myList.GetEnumerator(); } }
}
This doesn't create a copy, is readonly, and cannot be cast back to list.
Edit: this only works with yield return. It is lazy evaluated this way, I do not know whether that is an issue for you or not.
You can use List<T>.AsReadOnly
method to expose a thin read-only wrapper of your list. There will be no additional copying, and the caller will "see" changes to the original array done inside your method instantaneously:
public ReadOnlyCollection<object> MyList { get { return _myList.AsReadOnly(); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With