2016-07-05 2 views
0

У меня возникает довольно странная проблема. Я повторяю тип List и в моем цикле присваиваю переменную итератора другому локальному объекту. Теперь изменение чего-либо в этом локальном объекте вызывает изменения в списке, в котором цикл выполняется итерацией. Позвольте мне прояснить это с помощью образца кода.Вычисления внутри цикла Foreach, производящие значения итерирующего списка

var balances = DBHelperADO.Select("select * from Orders"); 
// balances is of type List<MyModel> 

foreach (var item in balances) 
{ 
    MyModel model = new MyModel(); 
    model = item; 
    var thisQty = details.Where(x => x.Code == item.Code).Sum(x => x.QTY); 

    // details is another List<MyModel> holding values from the GUI 

    model.BLNC = model.BLNC - thisQty; 
    model.VAL = (model.BLNC == 0) ? 0 : model.VAL - (thisQty * model.RATE); 
    model.TABLE = "Orders"; 
    toUpdate.Add(model); // toUpdate is a List<MyModel>      
} 

Теперь я понимаю, что переменная-итератор (в данном случае пункт) только для чтения, и когда я пишу:

модель = пункт;

Я делаю копию моего пункта значения. Но когда я делаю вычисления на объекте модели, он вызывает те же изменения в списке весов.

Я не понимаю, почему это влияет на список весов. Я выполняю расчеты по локальным областям модель объект. Тогда почему они отражают список итераций (балансов).

Пожалуйста, помогите мне, что я делаю неправильно.

С уважением

ответ

3

Я предполагаю, что тип элементов в остатках является класса типа и не структуры.

Так что хранится в item и model является ссылка к например этого класса. Когда вы назначаете model = item;, вы не копируете экземпляр, а только ссылка на экземпляр.

Когда вы получаете доступ к свойству этого экземпляра через model.BLNC = ..., вы изменяете свойства исходного экземпляра. Это то же самое, что и вызов item.BLNC = ...

Исходная строка MyModel model = new MyModel() довольно устарела, поскольку вы переписываете ссылку на этот новый экземпляр.

Чтобы сделать реальную копию, вы можете попробовать что-то вроде

MyModel model = new MyModel 
{  
    BLNC = item.BLNC, 
    VAL = item.VAL, 
    TABLE = "Orders" 
    // ... copy further properties 
}; 

Вы также можете полностью переписать цикл с LINQ Select заявление, как это:

var toUpdate = balances.Select(item => 
    { 
     var thisQty = details.Where(x => x.Code == item.Code).Sum(x => x.QTY); 
     var blnc = item.BLNC - thisQty; 
     return new MyModel 
     { 
      BLNC = blnc, 
      VAL = (blnc == 0) ? 0 : item.VAL - (thisQty * item.RATE), 
      RATE = item.RATE, 
      TABLE = "Orders" 
     }; 
    }).ToList(); 

Вы, возможно, придется скопируйте дополнительные свойства вашего класса MyModel из item в новый экземпляр. И может быть необходимо использовать balances.AsEnumerable(), если есть проблемы с вложенными запросами.

+0

СПАСИБО много. Выбор LINQ очень изящный. –

3

model = item; делает ссылку, не копировать.

model.BLNC = model.BLNC - thisQty; обновляет ссылку, то есть обновляет значение в исходном объекте.

toUpdate.Add(model); добавляет ссылку назад к исходному объекту в первоначальном списке в новый список.

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