问题
I just looked into IReadOnlyList<T>
to create readonly list. But I think it is not 100% readonly. I can not add/remove the item from the list but I can still modify the members.
Consider this example.
class Program
{
static void Main(string[] args)
{
List<Test> list = new List<Test>();
list.Add(new Test() { MyProperty = 10 });
list.Add(new Test() { MyProperty = 20 });
IReadOnlyList<Test> myImmutableObj = list.AsReadOnly();
// I can modify the property which is part of read only list
myImmutableObj[0].MyProperty = 30;
}
}
public class Test
{
public int MyProperty { get; set; }
}
To make it truly readonly I have to make MyProperty
as readonly. This is a custom class, it's possible to modify the class. What if my list is of inbuilt .net class which has both getter & setter properties? I think in that case I have to write a wrapper of that .net class which only allows reading the value.
Is there any way to make the existing classes immutable?
回答1:
A truly immutable class is one whose properties and fields are all read-only. This definition is recursive in that all classes contained within this class's fields and properties must ALSO be read only. Your read-only list is not truly immutable, because the contents of the list are NOT immutable since as you said you can modify them. The individual items in the list would have to be read-only as well for the IReadOnlyList<T>
to truly be immutable.
回答2:
You're confusing the terms immutable and read-only.
A read-only object is an object that does not expose any way to change it. ReadOnlyCollection<T>
(returned by AsReadOnly()
) is a good example). However, IEnumerable<T>
is also read-only.
The important distinction is that read-only objects are allowed to change.
If you write list.Add(new Test())
, your read-only collection (which just wraps list
) will have changed.
Read-only collections are useful for designing safe APIs, where only the owner of the collection is allowed to change it.
However, it won't do any good for thread-safety.
An immutable object is an object that cannot change at all, no matter what happens (Reflection doesn't count). string
is an excellent example of an immutable class; the value of an existing string
instance can never change, no matter what happens. (barring reflection, unsafe code, and certain marshalling tricks)
.Net does not have any built-in immutable collections, but the CLR team released a library of immutable collection types on NuGet.
Truly immutable objects are intrinsically thread-safe. Since there is no way to modify them, there is no chance that other threads will observe an inconsistent instance.
You're asking about deep immutability.
An object is deeply immutable if every object recursively accessible through its properties (the entire object graph) is itself deeply immutable.
You can't make a deeply immutable object unless you make an immutable version of every class it needs to reference. These immutable versions need to copy the state from the mutable original classes; they cannot simply wrap the original instance, or it would still be mutable though the inner instances.
You could instead make a deeply read-only object by making a read-only wrapper around the mutable class.
For more information, see my blog.
来源:https://stackoverflow.com/questions/17012323/how-to-make-class-truly-immutable