C# 像'ToArray'和'ToList'这样的扩展方法是按引用还是按值操作的?

C# 像'ToArray'和'ToList'这样的扩展方法是按引用还是按值操作的?,c#,C#,比如说,我班上有一本私人词典或一张单子。我想返回一个只读枚举器,以便其他人可以遍历列表,但无权修改项目 我希望返回原始项/元素的副本,而不是围绕原始项/元素创建包装器类。像original.ToList().GetEnumerator()这样的东西会返回一个引用原始项的列表,还是返回一个包含原始项副本的列表 我应该注意,我还需要索引(即按索引访问项目,但仍无法修改它们)。这些方法创建集合的新实例,但项目引用仍将指向旧项目。换句话说,消费者无法更新您的内部集合,但他们可以自己更新项目 假设您对修改

比如说,我班上有一本私人词典或一张单子。我想返回一个只读枚举器,以便其他人可以遍历列表,但无权修改项目

我希望返回原始项/元素的副本,而不是围绕原始项/元素创建包装器类。像
original.ToList().GetEnumerator()
这样的东西会返回一个引用原始项的列表,还是返回一个包含原始项副本的列表


我应该注意,我还需要索引(即按索引访问项目,但仍无法修改它们)。

这些方法创建集合的新实例,但项目引用仍将指向旧项目。换句话说,消费者无法更新您的内部集合,但他们可以自己更新项目

假设您对修改项进行了适当的封装,这种方法会起作用,不过对于较大的列表来说,它会占用一些内存,因为您需要为每个新的项引用分配内存。这就是为什么返回包装器通常是首选的原因之一:它减少了包装器类的单个实例所需的额外内存。

直接调用

original.ToList<MyType>()

假设您的类有一个构造函数,它自己构造一个实例,并生成一个拷贝,类似于C++的复制构造函数,这将产生一个对象的拷贝列表。

<代码> toist](< /代码>和<代码> TrayRe())/代码>都按值工作。它们只是将值从原始的
IEnumerable
复制到新容器中


但是被复制的值很可能是引用

我曾考虑过在我的
GetEnumerator
中执行类似(psueCode):
返回newInstanceOfMyItem(valuesFromRealInstance)
。这是一种有效的方法吗?@SimpleCoder这是有效的,尽管可能有些过分。如果您希望确保使用者既不能更改列表,也不能更改项目本身,那么您可能希望为项目创建只读包装,然后返回该类的新实例。代码方面更清晰,消费者也更清楚,他们无法更新返回项目的值。对于
列表
,这非常简单,因为有一个
.AsReadOnly()
方法可以创建只读包装。当然,关于修改项目本身(如果它们是可变对象),dlev是怎么说的仍然适用。也许您不必重新创建对象,而可以定义一个它们实现的只读接口,并返回该接口的集合,而不是实现的集合。@dlev:我想我的代码段正试图传达您的建议。更好的显示方式是:
GetEnumerator
中返回新的MyClass(valuesFromInternalInstance)
。内部方法允许操作内部实例,公共方法提供除枚举器之外的只读访问。对标题问题的回答必须是:是的。我将考虑使用我的public <代码> GeEnguleReals< /Cult>方法中的第二个调用,然后返回迭代器。我不记得这是否会产生懒惰的评估(即不是每个项目都一次创建),但我很确定它会;就像我使用
返回新的MyType(item)
一样。这是正确的吗?实际上,
ToList
会导致每个元素都被实例化。不要介意。我想我可以返回
original。选择(item=>new MyType(item)).GetEnumerator()
,然后只会根据需要创建新项目。@SimpleCode这是正确的,LINQ会根据需要创建枚举元素,除非您调用
ToList
ToArray
。好的,太好了。我认为
return original.Select(item=>newmytype(item)).GetEnumerator()
是最简单的方法。
original.Select(item => new MyType(item)).ToList()