我有2个对象,我们称之为A
,B
和方法
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
答案 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
并将其克隆到新列表中。