当我尝试填充GridView时,我遇到了一个我无法理解的行为。请考虑以下代码:
DataTable table = GetStockMovement((int)ViewState[MOVEMENT_ID], false);
MovedProducts = from DataRow row in table.Rows
select new Product()
{
ProductId = (int)row["ProductId"],
ProductNo = row["ProductNo"].ToString(),
Name = row["ProductName"].ToString(),
Quantity = OriginalProducts.ToList().Find(p => p.ProductId == (int)row["ProductId"]).Quantity,
QuantityDiff = (int)row["Change"]
};
foreach (Product product in MovedProducts)
{
Console.WriteLine(product.ProductId + ": " + product.Quantity);
}
Console.WriteLine();
foreach (Product product in OriginalProducts)
{
product.Quantity -= 1000;
}
foreach (Product product in MovedProducts)
{
Console.WriteLine(product.ProductId + ": " + product.Quantity);
}
这个的输出是这样的:
1: 10
2: 4
1: -990
2: -996
Product.Quantity是一个int MovedProducts和OriginalProducts是存储在ViewState中的IEnumebles。
当我更改OriginalProducts时,为什么MovedProducts中的产品会发生变化?它们不是存储在内存中不同位置的两个完全不同的对象吗?
如果我没有使用LINQ表达式:
List<FPRSProduct> completedProducts = new List<FPRSProduct>();
foreach (DataRow row in table.Rows)
{
Product tmp = new Product();
tmp.ProductId = (int)row["ProductId"];
tmp.ProductNo = row["ProductNo"].ToString();
tmp.Name = row["ProductName"].ToString();
tmp.Quantity = OriginalProducts.ToList().Find(p => p.ProductId == (int)row["ProductId"]).Quantity;
tmp.QuantityDiff = (int)row["Change"];
completedProducts.Add(tmp);
}
一切都按照我的预期进行,即在更改OriginalProducts的数量之前和之后得到相同的数字。
答案 0 :(得分:2)
LINQ利用我们称之为延迟执行的东西。当你写出一个linq查询时,你实际上并没有执行查询定义的任务......你只是在定义它。查询定义的行为在使用时执行...在您的情况下,在两个foreach语句中执行。查询对于每个foreach执行TWICE,因此即使数据被复制......它也会在两个不同的时间点从源复制两次。 MovedProducts周围的第二个foreach正在检索OriginalProducts中的更新数据,因为查询的执行将推迟到第二个foreach实际执行。
请注意链接查询的“select new”子句中的这一KEY代码行:
Quantity = OriginalProducts.ToList().Find(p => p.ProductId == (int)row["ProductId"]).Quantity,
由于您在第一个和第二个foreach之间更新OriginalProducts,即使您正在创建distinc, new Product对象列表...因为延迟了查询处理,您执行上面的行每个产品两次。一次为第一次foreach,再一次为第二次foreach。