我有一个List<Cat>
where Cat
is astruct
有一个 Id 和一个名称。
如何更改 id 为 7 的猫的名称?
我做了(不假思索)
var myCat = catList.Single(c => c.Id == 7);
mycat.Name = "Dr Fluffykins";
但当然,结构是值类型。那么是否可以使用这样的技术,或者我是否必须更改.Single
为for
循环并存储索引以将其替换为更新的结构?
因为struct
s 是值类型,并且因为值类型被复制,所以myCat
最终得到了列表中 cat 的副本。您需要对struct
自身进行操作,而不是对其副本进行操作。
struct
此外,只有当它们是单个变量或数组的一部分时,您才能直接修改 s 的字段。List<T>
的索引器返回一个副本,因此 C# 编译器会产生“无法修改值类型”错误。
我知道的唯一解决方案(没有制作Cat
或class
重新分配修改后的副本)是制作catList
一个数组:
var indexOf = catArray
.Select((Cat, Index) => new {Cat, Index})
.Single(p => p.Cat.Id == 7).Index;
catArray[indexOf].Name = "Dr Fluffykins";
要更新列表中 ID 为 7 的项目的值,必须首先找到它在列表中的位置。一旦知道它的索引,就可以使用适用于所有暴露字段结构的常规方法对其进行更新:
int index = myList.Find( it => it.ID == 7);
if (index >= 0)
{
var temp = myList[index];
temp.Name = "Dr Fluffykins";
myList[index] = temp;
}
请注意,有些人认为结构不如类,因为如果没有最后一行,上述代码将永远无法工作。我认为相反:在许多情况下,它们是优越的,因为仅仅知道某物是一个暴露字段结构就足以知道最后一行是必要的和充分的。相比之下,如果所讨论的类型是一个可变类,那么代码,无论有没有最后一行,都可能按预期工作,或者可能有意想不到的副作用。
顺便说一句,如果要使用Id
很多,我建议使用 aDictionary<int, Cat>
而不是 a List<Cat>
。或者,您可以使用 aCat[]
和 aDictionary<int,int>
来跟踪数组中不同猫的位置。后一种方法的一个优点是,与 aCat[]
不同List<Cat>
,可以简单地说:
myArray[index].Name = "Dr Fluffykins";
直接更新数组中的项目。这种方法非常高效。或者,您可以编写一个类似List<T>
类的类,其中包含一个方法 "ActOnItem(int index, ref T it)
和ActOnItem<TParam1>(int index, ref T it, ref TParam1 param1)
方法,可以调用它们myList.ActOnItem(index, (ref Cat it)=>it.Name = "Dr Fluffykins");
或 -- 如果theNewName
是一个变量,myList.ActOnItem(index, (ref Cat it, ref string TheNewName)=>it.Name = theNewName);
请注意,可以将其存储theNewName
到项目而不将其作为ref
或非 ref 参数传递,但是 lambdas关闭局部变量比不关闭的要慢得多。