Can't change struct's members value inside generic collections

前端 未结 3 1932
灰色年华
灰色年华 2020-12-06 18:25

Imagine this struct :

        struct Person
        {
             public string FirstName { get; set; }
             public string LastName { g         


        
相关标签:
3条回答
  • 2020-12-06 18:49

    Redo your struct as such:

        struct Person
        {
             private readonly string firstName;
             private readonly string lastName;
             public Person(string firstName, string lastName)
             {
                 this.firstName = firstName;
                 this.lastName = lastName;
             }
             public string FirstName { get { return this.firstName; } }
             public string LastName { get { return this.lastName; } }
        }
    

    And following code as :

        var list = new List<Person>();
        list.Add(new Person("F1", "L1"));
        list.Add(new Person("F2", "L2"));
        list.Add(new Person("F3", "L3"));
    
        // Can modify the expression because it's a new instance
        list[1] = new Person("F22", list[1].LastName);
    

    This is due to the copy semantics of struct. Make it immutable and work within those constraints and the problem goes away.

    0 讨论(0)
  • 2020-12-06 18:58

    Obviously a part of the question is still unanswered. What is difference between List<Person> and Person[]. In term of getting element by index the List calls indexer (method) which returns copy of value-type instance, in opposite array by index returns not a copy but managed pointer to element at the index (used special IL instruction ldelema).

    Of course mutable value-types are evil as mentioned in other answers. Look at the simple example.

    var en = new {Ints = new List<int>{1,2,3}.GetEnumerator()};
    while(en.Ints.MoveNext())
    {
        Console.WriteLine(x.Ints.Current);
    }
    

    Surprised?

    0 讨论(0)
  • 2020-12-06 19:07

    When you return the struct via the List[] indexer, it returns a copy of the entry. So if you assigned the FirstName there, it would just be thrown away. Hence the compiler error.

    Either rewrite your Person to be a reference type class, or do a full reassignment:

    Person person = list[1];
    person.FirstName = "F22";
    list[1] = person;
    

    Generally speaking, mutable structs bring about issues such as these that can cause headaches down the road. Unless you have a really good reason to be using them, you should strongly consider changing your Person type.

    Why are mutable structs “evil”?

    0 讨论(0)
提交回复
热议问题