无法更改泛型集合中struct的成员值

时间:2013-02-18 20:55:10

标签: c# .net struct generic-list generic-collections

想象一下这个struct

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

以下代码:

        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";

当我想更改Property的值时,它会给我以下错误:

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

然而,当我尝试在诸如Person[]之类的数组中更改它时,它没有任何错误。当使用泛型集合时,我的代码是否有任何问题?

3 个答案:

答案 0 :(得分:13)

当您通过struct索引器返回List[]时,它会返回条目的副本。因此,如果您在那里分配了FirstName,它就会被丢弃。因此编译错误。

将您的Person重写为参考类型class,或者进行全面重新分配:

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

一般来说,可变的结构会带来诸如此类的问题,这些问题可能导致头痛。除非您有充分的理由使用它们,否则您应该强烈考虑更改Person类型。

Why are mutable structs “evil”?

答案 1 :(得分:4)

显然问题的一部分仍然没有答案。 List<Person>Person[]之间有何区别?在按索引获取元素方面,List调用返回值类型实例副本的索引器(方法),在索引的相反数组中,不返回副本,而是在索引处返回元素的托管指针(使用特殊的IL指令{ {3}})。

当然,其他答案中提到的可变价值类型是邪恶的。看一下这个简单的例子。

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

惊奇?

答案 2 :(得分:0)

重做你的struct

    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; } }
    }

以下代码为:

    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);

这是由struct的复制语义引起的。使它不可变并在这些约束下工作,问题就消失了。