How to ensure the invariability of the general

This example is provided in C #, but the question really applies to any OO language. I would like to create a universal, immutable class that implements IReadOnlyList. In addition, this class must have a basic generic IList that cannot be changed. The class was originally written as follows:

public class Datum<T> : IReadOnlyList<T>
{
    private IList<T> objects;
    public int Count 
    { 
        get; 
        private set;
    }
    public T this[int i]
    {
        get
        {
            return objects[i];
        }
        private set
        {
            this.objects[i] = value;
        }
    }

    public Datum(IList<T> obj)
    {
        this.objects = obj;
        this.Count = obj.Count;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
    public IEnumerator<T> GetEnumerator()
    {
        return this.objects.GetEnumerator();
    }
}

However, this is not unchanged. As you can probably tell, changing the original IList 'obj' modifies the Datum 'objects'.

static void Main(string[] args)
{
    List<object> list = new List<object>();
    list.Add("one");
    Datum<object> datum = new Datum<object>(list);
    list[0] = "two";
    Console.WriteLine(datum[0]);
}

This writes two to the console. Since the Datum point is unchanged, this is not normal. To solve this problem, I rewrote the Datum constructor:

public Datum(IList<T> obj)
{
    this.objects = new List<T>();
    foreach(T t in obj)
    {
        this.objects.Add(t);
    }
    this.Count = obj.Count;
}

, , "". . , Datum , ?

static void Main(string[] args)
{
    List<object> list = new List<object>();
    List<List<object>> containingList = new List<List<object>>();
    list.Add("one");
    containingList.Add(list);
    Datum<List<object>> d = new Datum<List<object>>(containingList);
    list[0] = "two";
    Console.WriteLine(d[0][0]);
}

, , "". , : ?

+4
4

. , , , . :

1. struct -

where T : struct Datum<T>. struct , class, ( Servy). , , , string , .

var e = new ExtraEvilStruct();
e.Mutable = new Mutable { MyVal = 1 };
Datum<ExtraEvilStruct> datum = new Datum<ExtraEvilStruct>(new[] { e });
e.Mutable.MyVal = 2;
Console.WriteLine(datum[0].Mutable.MyVal); // 2

2.

, . , . , , , .

public interface IImmutable
{
    // this space intentionally left blank, except for this comment
}
public class Datum<T> : IReadOnlyList<T> where T : IImmutable

3. !

, (, Json.NET), . : , . : , , . .

public Datum(IList<T> obj)
{
    this.objects =
      JsonConvert.DeserializeObject<IList<T>>(JsonConvert.SerializeObject(obj));
    this.Count = obj.Count;
}

, Datum<T>, , . (, Dictionary , TKey GetHashCode Equals , ), .

+4

. . , , , . .

0

, , T , , . - , .

, , , . .

- :

public class Datum<T> : IReadOnlyList<T>
{
    private IList<string> objects;
    public T this[int i] {
        get { return JsonConvert.DeserializeObject<T>(objects[i]); }
        private set { this.objects[i] = JsonConvert.SerializeObject(value); }
    }

    public Datum(IList<T> obj) {
        this.objects = new List<string>();
        foreach (T t in obj) {
            this.objects.Add(JsonConvert.SerializeObject(t));
        }
        this.Count = obj.Count;
    }

    public IEnumerator<T> GetEnumerator() {
        return this.objects.Select(JsonConvert.DeserializeObject<T>).GetEnumerator();
    }
}
-1

, , - . ?

Thus, serialization suggestions and, therefore, may allow you to do it in a cracked way, but it’s better to decide if you need to do this with a collection of immutable elements that try to change them other than your own code? It might be better not to mutate things, rather than trying to make them immutable.

-1
source

All Articles