Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does AsReadOnly make sense if you cast it in an IEnumerable eventually?

Tags:

c#

ienumerable

I saw some code in this project that got my attention.

There is a simple method that calls AsReadOnly on a List. Instead of doing something with the ReadOnlyCollection the method returns it immediately and implicitly casts it into an IEnumerable.

What is the point of using AsReadOnly if you only need an Enumerable?

Would AsEnumerable be a better option?

private List<PaymentMethod> _paymentMethods = new List<PaymentMethod>();

public IEnumerable<PaymentMethod> PaymentMethods => 
        _paymentMethods.AsReadOnly();
like image 998
Nick Avatar asked Dec 23 '22 21:12

Nick


1 Answers

What is the point of using AsReadOnly if you only need an enumerable?

The point is that AsReadOnly ensures that a low-trust hostile or buggy caller cannot cast back to a mutable collection.

Would AsEnumerable be a better option?

No. Try this:

List<int> list = new List<int>{ 10, 20, 30 };
...
IEnumerable<int> seq = list.AsEnumerable();
// Or (IEnumerable<int>)list, or whatever.
...
List<int> list2 = (List<int>)seq;
list2[0] = 40;

And now we have changed list[0].

But AsReadOnly prevents this, as the read-only wrapper cannot be cast back to List<int>.

Remember, AsEnumerable is just a visually nicer way to write a cast, and casts that are reference conversions are reference conversions. The reference is not changed and it can be changed back to its actual type!

Of course, a hostile or buggy caller that has full trust can arbitrarily break the safety system, because full trust means full trust. A read only collection maintains a reference to the original collection, and that reference can be retrieved via reflection.

Also, remember that read-only means read-only, not unchanging. A read-only wrapper around a mutable collection can still be observed to change; you just cannot change it via the read-only wrapper.

like image 114
Eric Lippert Avatar answered Mar 29 '23 23:03

Eric Lippert