可以';t更改结构';s成员在泛型集合中的值

本文关键字:集合 泛型 结构 可以 成员 | 更新日期: 2023-09-27 17:59:52

想象一下这个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[]之类的数组中更改它时,它没有任何错误。与泛型集合一起使用时,我的代码有问题吗?

可以';t更改结构';s成员在泛型集合中的值

通过List[]索引器返回struct时,它会返回条目的副本。所以,如果你把FirstName分配到那里,它就会被扔掉。因此出现编译器错误。

要么将Person重写为引用类型class,要么进行完全重新分配:

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

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

为什么可变结构是"邪恶的"?

显然,问题的一部分仍未得到解答。List<Person>Person[]有什么区别。在按索引获取元素方面,List调用indexer(方法),该方法返回值类型实例的副本,在相反的按索引数组中,返回的不是副本,而是指向索引处元素的托管指针(使用特殊的IL指令ldelema)。

当然,正如其他答案中提到的那样,可变值类型是邪恶的。看看这个简单的例子。

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

惊讶吗?

按如下方式重做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的复制语义。让它不可变,并在这些约束条件下工作,问题就会消失。