我似乎有一个奇怪的问题,每当我尝试更改集合中项目的值时,它会影响包含相同初始值的所有其他值。
以下是一个例子:
public class Product : ICloneable
{
public int Id { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public Product()
{
Id = 0;
Quantity = 0;
}
public Clone()
{
return (Product)this.MemberwiseClone();
}
}
...
private static IEnumerable<Product> GetProducts(Product product, int quantity)
{
for (int i = 0; i < quantity; i++)
{
yield return product.Clone();
}
}
...
IEnumerable<Product> myProducts = Enumerable.Empty<Product>();
Product product1 = new Product() { Id = 0, Name = "Buzz Cola" };
Product product2 = new Product() { Id = 1, Name = "Choco Bites" };
myProducts = myProducts.Concat(GetProducts(product1, 2));
myProducts = myProducts.Concat(GetProducts(product2, 1));
//Now set the quantity of the first product to be 1.
myProducts.ElementAt(0).Quantity = 1;
foreach(Product product in myProducts)
{
Console.WriteLine(string.Format("Id: {0} Quantity: {1}", product.Id, product.Quantity));
}
//Output:
//Id: 0 Quantity: 1
//Id: 0 Quantity: 1 //NO!
//Id: 1 Quantity: 0
有什么想法吗?
非常感谢!
更新 我已根据建议更新了问题以包含克隆()。但输出仍然相同。
答案 0 :(得分:3)
Product
是一种引用类型,您的GetProducts
方法只会产生对同一Product
个对象的多个引用。
这就是更新一个实例更新任何其他实例的原因 - 它们都是对同一个对象的引用。
答案 1 :(得分:1)
我猜它会引用ID = 0的第一个实例两次,而不是像你期望的那样引用两个独立的实例。
尝试将第三个实例的ID从0更改为&gt; 2,看看是否“修复了”它。
答案 2 :(得分:1)
在WriteLine循环中纠正一些拼写错误(请复制/粘贴工作代码)后,错误无法重现,我的输出是:
Id: 0 Quantity: 1
Id: 1 Quantity: 0
Id: 0 Quantity: 0
更改后:
您只创建了2个实例,因此您遇到了一个非常简单的事实,即您有3个引用但只有2个实例。输出应该是应有的。如果您还打印Name属性,它会变得更清晰。
但是你明显想要的,在那个非常复杂的Enumerator / Concat故事的某个地方就是克隆你的产品。
Charlie Salts可以取消删除他的答案,他是对的。
答案 3 :(得分:1)
myProducts.ElementAt(0)和myProducts.ElementAt(1)都将引用同一个对象。
不确定解决此问题的最佳方法: 也许在添加到列表之前,请检查您是否已经引用了该对象?如果你这样做,deep clone该对象并插入它......
答案 4 :(得分:1)
您需要克隆方法或复制构造函数。
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public Product()
{
this.Id = 0;
this.Name = null;
this.Quantity = 0;
}
public Product(Product product)
{
this.Id = product.id;
this.Name = product.Name;
this.Quantity = product.Quantity;
}
}
IList<Product> myProducts = new List<Product>();
Product product1 = new Product() { Id = 0, Name = "Buzz Cola" };
Product product2 = new Product() { Id = 1, Name = "Choco Bites" };
Product product3 = new Product(product1); // Use copy-constructor.
myProducts.Add(product1);
myProducts.Add(product2);
myProducts.Add(product3);
myProducts[0].Quantity = 1;
现在一切都应该没问题。您可以将它与cloniung方法一起使用,以一次生成大量克隆。
请注意,此代码仍然非常糟糕 - 您正在使用相同的ID创建不同的产品实例。我可以猜测,但你想建立一个类似购物车的东西,购物车上有数量和产品的购物车吗?如果是,您应该考虑将产品类拆分为两个类。并考虑您的属性aganin的可访问性。
public class Product
{
public Int32 Id { get; private set; }
public String Name { get; private set; }
}
public class ShoppingCartItem
{
public Product Product { get; private set; }
public Int32 Quantity { get; set; }
}
public class ShoppingCart
{
public IList<ShoppingCartItem> Items { get; private set; }
}
这解决了您当前的问题,因为不再需要克隆产品。
答案 5 :(得分:-1)
改为使用索引器。
myProducts[0].Quantity = 1