通用列表和值引用

时间:2015-09-30 09:36:44

标签: c#

我有2个对象,我们称之为AB和方法

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;
}

因此,在完成该方法之后,我的原始列表b已更改了值Name字段(string),但我没有将其作为ref和我&#39传递; m使用应该返回elemens副本的where吗?所以我的问题是为什么我的列表b改变了它的价值?

List<B> originalList = ...;
List<B> newList = DoSomething(ref a, originalList);
//now originalList have changed Name field values

6 个答案:

答案 0 :(得分:4)

实际上List<B>是B元素的引用列表。引用列表已更改,但引用仍指向相同的对象。

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

答案 1 :(得分:2)

您;实际上正在执行浅层处理:您复制对象的引用,而不用创建对象的

  // 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(); 

如果要克隆项目,则必须为ICloneable课程正确实施B界面(以确保深层处理

答案 2 :(得分:1)

  

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

因为虽然您分配了新列表,但它们现在仍然将指向同一个B实例。在将新实例添加到新列表之前,您尚未创建新实例。

如何克隆现有对象的示例是通过复制构造函数

public class B
{
    public string Name { get; }
    public B(B other)
    {
        Name = other.name;
    }
}

现在,当您想要创建列表时,您可以:

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

答案 3 :(得分:0)

除了简单类型(int,double等)之外,C#中的所有类型都作为引用传递。如果要创建副本,则需要手动执行此操作

答案 4 :(得分:0)

当b.Where(..)。ToList然后只创建副本。返回IEnumerable,允许你使用foreach循环进行迭代。

答案 5 :(得分:0)

Where(t => IsOk(t));

不会创建其所调用的IEnumerable的深层副本。它遍历集合并返回与isOk()条件匹配的项目。这意味着它会创建一个新列表,但项目是相同的。

如果您想创建每个项目的副本,您应该对项目实施ICloneable并将其克隆到新列表中。

相关问题