Це відомий підводний камінь людям, які змочують ноги за допомогою LINQ:
public class Program
{
public static void Main()
{
IEnumerable<Record> originalCollection = GenerateRecords(new[] {"Jesse"});
var newCollection = new List<Record>(originalCollection);
Console.WriteLine(ContainTheSameSingleObject(originalCollection, newCollection));
}
private static IEnumerable<Record> GenerateRecords(string[] listOfNames)
{
return listOfNames.Select(x => new Record(Guid.NewGuid(), x));
}
private static bool ContainTheSameSingleObject(IEnumerable<Record>
originalCollection, List<Record> newCollection)
{
return originalCollection.Count() == 1 && newCollection.Count() == 1 &&
originalCollection.Single().Id == newCollection.Single().Id;
}
private class Record
{
public Guid Id { get; }
public string SomeValue { get; }
public Record(Guid id, string someValue)
{
Id = id;
SomeValue = someValue;
}
}
}
Це надрукує "False", тому що для кожного імені, створеного для створення оригінальної колекції, функція select продовжує переоцінюватися, а отриманий Record
об'єкт створюється заново. Щоб виправити це, ToList
можна було додати простий дзвінок до в кінці GenerateRecords
.
Яку перевагу сподівався отримати Microsoft, реалізуючи її таким чином?
Чому б реалізація не просто кешувала результати внутрішнім масивом? Однією конкретною частиною того, що відбувається, може бути відкладене виконання, але це все-таки може бути здійснено без такої поведінки.
Після того, як даний член колекції, повернуту LINQ, був оцінений, яка перевага надається, якщо не зберігати внутрішню посилання / копію, а замість того, щоб перерахувати той самий результат, як поведінка за замовчуванням?
У ситуаціях, коли є певна потреба в логіці того ж члена колекції, який перераховується знову і знову, схоже, що це може бути визначено за допомогою необов'язкового параметра, і що поведінка за замовчуванням могла інакше. Крім того, швидкість переваги, що отримується відкладеним виконанням, в кінцевому рахунку зменшується часом, необхідним для постійного перерахунку одних і тих же результатів. Нарешті, це заплутаний блок для тих, хто не є новим для LINQ, і це може призвести до тонких помилок у кінцевому рахунку будь-якої програми.
Яка перевага у цьому є, і чому Microsoft прийняла це, здавалося б, дуже обдумане рішення?
return listOfNames.Select(x => new Record(Guid.NewGuid(), x)).ToList();
Це дає вам "кешовану копію". Проблема вирішена.