gpt4 book ai didi

c# - 为什么不能修改元组类型列表元素的值?

转载 作者:行者123 更新时间:2023-12-03 15:39:50 32 4
gpt4 key购买 nike

在C#8.0中,我可以通过访问字段名称直接在元组中修改值:

(string name, int score) student = ("Tom", 100);
student.name = "Jack";
Console.WriteLine(student);
而且我可以按如下方式修改列表元素的属性:
var list = new List<Student>();  // assume I have a Student class which has a Name property
list.Add(new Student { Name = "Tom" });
list[0].Name = "Jack";
Console.WriteLine(list[0]);
但是为什么我不能像这样修改元组类型元素的值?
var list = new List<(string name, int score)>();
list.Add(("Tom", 100));
list[0].name = "Jack"; // Error!
Console.WriteLine(list[0]);

最佳答案

元组(ValueTuple)是一个结构。与其像Student示例中那样返回值的引用,不如实际上是接收元组的副本
对该副本所做的更改不会反射(reflect)在列表中,将被丢弃。编译器足够聪明,可以识别此问题,并阻止您执行此操作。
如果编译成功,它将类似于以下内容:

var list = new List<(string name, int score)>(); list.Add(("Tom", 100));
var copy = list[0];
copy.name = "Jack";
Console.WriteLine(copy.name); // Jack
Console.WriteLine(list[0].name); // still Tom
如果您使用不正确,可变结构可能很危险。编译器只是在完成其工作。
您可以通过以下方法解决此问题:
var list = new List<(string name, int score)>(); list.Add(("Tom", 100));
var copy = list[0];
copy.name = "Jack";
list[0] = copy; // put it back
Console.WriteLine(copy.name); // Jack
Console.WriteLine(list[0].name); // Jack
Try It Online
如果您使用数组 (string, int)[]而不是 List<(string, int)>,则由于数组元素访问的工作方式,这不是问题:
var arr = new (string name, int score) [] { ( "Tom", 10 ) };
arr[0].name = "Jack";
Console.WriteLine(arr[0].name); // Jack
Try It Online
此行为不是 List或您的元组类型所独有的。您将在元素为值类型的任何集合中遇到此问题(除非它们当然提供 ref元素访问器)。
请注意,当具有通过方法调用进行突变的 可变值类型的 readonly字段时,也会出现类似的问题。这可能更多 阴险,因为不会发出任何错误或警告:
struct MutableStruct { 
public int Val;
public void Mutate(int newVal) {
Val = newVal;
}
}
class Test {
private readonly MutableStruct msReadonly;
private MutableStruct msNormal;
public Test() {
msNormal = msReadonly = new MutableStruct(){ Val=5 };
}
public void MutateReadonly() {
Console.WriteLine(msReadonly.Val); // 5
msReadonly.Mutate(66); // defensive copy!
Console.WriteLine(msReadonly.Val); // still 5!!!
}
public void MutateNormal() {
Console.WriteLine(msNormal.Val); // 5
msNormal.Mutate(66);
Console.WriteLine(msNormal.Val); // 66
}
}
new Test().MutateReadonly();
new Test().MutateNormal();
Try It Online ValueTuple是框架和语言的重要补充。但是有一个原因,您经常会听到 [Mutable] structs are evil.在大多数情况下,您不应该达到这些限制。如果您发现自己经常陷入这种模式,建议您改用 record,它是一种引用类型(因此不会遇到这些问题),并且可以简化为类似元组的语法。

关于c# - 为什么不能修改元组类型列表元素的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66840188/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com