2016-03-04 1 views
0

Я хочу обновить каждое свойство класса в IEnumerable из внешнего списка.Обновление свойства класса внутри Enumerable.Zip linq C#

class MyClass 
{ 
    public int Value { get; set; }    
} 

Я попытался следующие

var numbers = new List<int>() { 1, 2, 3 }; 
var myclasses = Enumerable.Repeat(new MyClass(), numbers.Count); 

myclasses.Zip(numbers, (a, b) => a.Value = b).ToList();   // Set each property [Not working as expected] 
myclasses.ToList().ForEach(x => Console.WriteLine(x.Value));  // Print all properties 

Я ожидаю, что предыдущий код будет установлен Value свойство в myclasses с 1,2,3 respectivelly. Но этот набор кодов 3 в каждой собственности и гравюр:

OUTPUT: 
3 
3 
3 

Я не понимаю такого поведения. Может кто-нибудь объяснить мне, почему это произошло, и что это правильный способ сделать это с помощью LINQ.

ответ

1

Enumerable.Repeat(a, b) генерирует последовательность, которая содержит b раз a. Таким образом, вы получаете последовательность, которая содержит три раза тот же экземпляр (вы создаете экземпляр одинnew MyClass()).

Так последним исполнением a.Value = b установить Value свойство вашего единственного MyClass инстанции 3 и x в вашем WriteLine всегда тот же экземпляр , содержащий Value = 3.

Лучший способ создать myclasses бы

var myclasses = Enumerable.Range(1, numbers.Count).Select(i => new MyClass()); 

Примечание что это often a bad idea создавать последовательности с побочными эффектами. Вы на самом деле не используете последовательность, возвращаемую Zip, но используйте этот запрос только для его побочных эффектов внутри вашей лямбда.

Я думаю, в вашем реальном случае создание myclasses и обновление через Zip более разборчиво, чем в вашем вопросе. Но если нет, то вы могли бы свести все это к этому:

var myclasses = numbers.Select(i => new MyClass { Value = i }); 

UPDATE

Причина, почему вы теперь только получить 0 сек как выход является отложила exeuction (опять-таки: с помощью функциональных методов программирования как linq только для его побочных эффектов, является сложным).

Непосредственное решением является добавление ToList к созданию:

var myclasses = Enumerable.Range(1, numbers.Count).Select(i => new MyClass()).ToList(); 

Без этого, классы инстанцируются только на этой линии:

myclasses.Zip(numbers, (a, b) => a.Value = b).ToList(); 

и созданные классы возвращенных как последовательность, которая затем превращается в List по ToList(). Но вы не используете это возвращаемое значение.

Таким образом, в следующей строке

myclasses.ToList().ForEach(x => Console.WriteLine(x.Value)); 

вы создающих новые экземпляры классов.

myclasses, как вы определили, что это только запрос, не ответ на этот запрос.

Так мое окончательное предложение:

var myclasses = Enumerable.Range(1, numbers.Count).Select(i => new MyClass()); 
var updatedClasses = myclasses.Zip(numbers, (a, b) => {a.Value = b; return a;}).ToList(); 
updatedClasses.ForEach(x => Console.WriteLine(x.Value)); 

Примечание, что я изменил лямбда в Zip вернуть экземпляр класса вместо int.

+0

Да, создание 'myclasses' отделено от вопроса, я только интересуюсь обновлениями с' Zip'. Я исправил создание 'myclassess', используя' Enumerable.Range', как вы писали, но это все еще не работает. В этом случае 'Zip' ничего не сделает (он будет печатать все нули). Опять же, я не понимаю, почему средство настройки свойств не вызывается. – Dejan

+0

@Petar Я обновил свой ответ, чтобы решить эту проблему. –

+0

Я не могу сказать, что сделал несколько ошибок всего в нескольких строках :). Tnx для хорошего объяснения. – Dejan