What is the best way to open a List <T> as read-only?
I have come across this design problem many times and have never found a solution for killers.
I want to open a collection that is editable in the class owner area, but is only available for other public areas.
Trial 1:
public class MyClass { private List<object> _myList = new List<object>(); public IEnumerable<object> MyList { get { return _myList; } } } A problem with this external code may simply return it back to the List and change, for example:
var x = ((List<object>)MyList); Test 2:
public class MyClass { private List<object> _myList = new List<object>(); public IEnumerable<object> MyList { get { return _myList.ToList(); } } } In this way, we prevent external modification, but create unnecessary overhead for copying the List many times.
Test 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 I'm currently using, but ReadOnlyCollection 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 an โidealโ way to do this? Thanks.
Did you try to return the counter?
public class MyClass { private List<object> _myList = new List<object>(); public IEnumerable<object> MyList { get { yield return _myList.GetEnumerator(); } } } This does not create a read-only copy and cannot be returned to the list.
Edit: this only works with return returns. It is lazily evaluated in this way, I donโt know if this is a problem for you or not.
You can use the List<T>.AsReadOnly to open a thin shell just for reading your list. There will be no additional copying, and the caller will instantly see changes to the original array executed inside your method:
public ReadOnlyCollection<object> MyList { get { return _myList.AsReadOnly(); } } The solution that I usually use and how much is because it is simply the following:
public IEnumerable<object> MyList { get { return _myList.Select(x => x); } } However, this requires using a version of .NET that supports Linq.
Looping with foreach is faster: less than 1 ms for Select and 0.1 seconds for ReadOnlyCollection . For ReadOnlyCollection I used:
public IEnumerable<object> MyROList { get { return new ReadOnlyCollection<object>(_myList); } } Use ReadOnlyCollection<T> as a wrapper - it uses your List<T> collection internally (using the same link, therefore does not copy anything, and any changes made to the list are also reflected in ReadOnlyCollection).
This is better than just suggesting an IEnumerable property, as it also contains indexing and counting information.
The .NET Framework 4.5 introduces two new interfaces: IReadOnlyCollection<T> and IReadOnlyList<T> . List<T> implements both interfaces.
Why don't you use the List<T>.AsReadOnly , see the code snippet below:
public class MyClass { private List<object> _myList = new List<object>(); public IList<object> MyList { get { return _myList.AsReadOnly(); } } }