2009-08-21 3 views
0

Я столкнулся с поведением, которое я не могу понять, когда пытаюсь заполнить 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 является ИНТ Н. MovedProducts и OriginalProducts являются IEnumerables, которые хранятся в ViewState.

Почему продукт в MovedProducts изменяется при изменении в OriginalProducts? Разве это не два совершенно разных объекта, хранящихся в разных местах в памяти?

Если я вместо 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.

ответ

2

LINQ использует то, что мы называем отложенным исполнением. Когда вы выписываете запрос linq, вы фактически не выполняете задачи, которые задает запрос ... вы просто определяете его. Поведение, определенное вашим запросом, выполняется в момент использования ... в вашем случае в двух операциях foreach. Запрос выполняется TWICE для EACH foreach, поэтому даже при копировании данных ... его копируется из источника дважды в два разных момента времени. Второй foreach вокруг вашего MovedProducts - это получение обновленных данных в вашем OriginalProducts, потому что выполнение запроса отложено до тех пор, пока второй foreach фактически не будет выполнен.

ПримечаниеЭтот KEY строка коды в «выбрать новый» пункт Вашего запроса ссылки:

Quantity = OriginalProducts.ToList().Find(p => p.ProductId == (int)row["ProductId"]).Quantity, 

Поскольку вы обновить OriginalProducts между первым и вторым Еогеаспом, даже если вы создаете distinc, новое список объектов продукта ... поскольку обработка запроса отложена, вы дважды выполняете вышеуказанную строку для каждого продукта. Один раз для первого foreach, и еще раз для второго foreach.

Смежные вопросы