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

这一生的挚爱 提交于 2019-11-26 21:49:54

问题


Imagine this struct :

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

And following code :

        var list = new List<Person>();
        list.Add(new Person { FirstName = "F1", LastName = "L1" });
        list.Add(new Person { FirstName = "F2", LastName = "L2" });
        list.Add(new Person { FirstName = "F3", LastName = "L3" });

        // Can't modify the expression because it's not a variable
        list[1].FirstName = "F22";

When I want to change Property's value it gives me the following error:

Can't modify the expression because it's not a variable

While, when I tried to change it inside an array such as Person[] it worked without any error.Is there any problem with my code when using with generic collections?


回答1:


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”?




回答2:


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?




回答3:


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.



来源:https://stackoverflow.com/questions/14945118/cant-change-structs-members-value-inside-generic-collections

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!