Это известная ловушка для людей, которые промокают ноги с помощью 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();
Это дает вам «кэшированную копию». Проблема решена.