C# 通用列表和值引用

C# 通用列表和值引用,c#,C#,我有两个对象,我们把它们叫做A,B和method List<B> DoSomething(ref A a, List<B> b) { List<B> newList = new List<B>(); // //Doing something to ref A // foreach(var elementOfB in b.where(...)) { //

我有两个对象,我们把它们叫做
A
B
和method

List<B> DoSomething(ref A a, List<B> b)
{
     List<B> newList = new List<B>();

     //
     //Doing something to ref A
     //

     foreach(var elementOfB in b.where(...))
     {
        //
        elementOfB.Name = "...";
        //
        newList.Add(elementOfB);
     }
     return newList;
}
实际上,
List
是对B元素的引用列表。引用列表已更改,但引用仍然指向相同的对象

如果您需要克隆对象,请查看此图

除了简单类型(int、double等)之外,C#中的所有类型都作为引用传递。如果要创建副本,需要在b.Where(..).ToList时手动执行此操作,然后只创建副本。Where返回IEnumerable,允许使用foreach循环进行迭代

Where(t => IsOk(t));
不创建调用它的
IEnumerable
的深度副本。它遍历集合并返回与isOk()条件匹配的项。这意味着它创建了一个新列表,但项目是相同的

若要创建每个项目的副本,应在项目上实现
ICloneable
,并将其克隆到新列表中。

;我们实际上在做浅层处理:复制对象的引用,而不创建对象的克隆:

  // Shallow copy (your actual implementation):
  // NewList is not b, but it contains references to objects in b
  var NewList = b
    .Where(item => ...)
    .ToList(); 

  // Deep copy (which probably you're looking for)
  // NewList doesn't contain any reference to any objects in b 
  var NewList = b
    .Where(item => ...)
    .Select(item => item.Clone()) // You need this, proving that Clone() makes a deep copy
    .ToList(); 
如果要克隆项目,必须为
B
类正确实现
ICloneable
接口(以确保深度覆盖)

为什么我的列表b改变了它的值

List<B> originalList = ...;
List<B> newList = DoSomething(ref a, originalList);
//now originalList have changed Name field values
因为虽然您分配了一个新列表,但它们现在仍然指向相同的
B
实例。在将它们添加到新列表之前,您尚未创建新实例

可以通过复制构造函数克隆现有对象的示例如下:

现在,如果要创建列表,请执行以下操作:

foreach(var elementOfB in b.Where(SomePredicate))
{
    elementOfB.Name = "...";
    newList.Add(new B(elementOfB));
}

否,其中迭代列表中的元素,不创建副本。您需要手动创建元素的副本为什么要做出这样的假设?OP表示元素的副本而不是列表
iclonable
不能保证任何东西。您可能应该向OP澄清,他仍然需要实现对象的深度复制。
ICloneable
的问题是,调用方不知道你在做什么类型的克隆。@Yuval Itzhakov:谢谢,非常想澄清一下。我已经编辑了答案。
foreach(var elementOfB in b.Where(SomePredicate))
{
    elementOfB.Name = "...";
    newList.Add(new B(elementOfB));
}