Essa é uma armadilha conhecida para as pessoas que estão molhando os pés usando o 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;
}
}
}
Isso imprimirá "False", porque para cada nome fornecido para criar a coleção original, a função de seleção continua sendo reavaliada e o Record
objeto resultante é criado novamente. Para corrigir isso, uma simples chamada para ToList
poderia ser adicionada no final de GenerateRecords
.
Que vantagem a Microsoft esperava obter ao implementá-la dessa maneira?
Por que a implementação não armazenaria em cache os resultados em uma matriz interna? Uma parte específica do que está acontecendo pode ser a execução adiada, mas isso ainda pode ser implementado sem esse comportamento.
Depois que um determinado membro de uma coleção retornada pelo LINQ é avaliado, qual é a vantagem de não manter uma referência / cópia interna, mas recalcular o mesmo resultado, como um comportamento padrão?
Nas situações em que há uma necessidade específica na lógica de o mesmo membro de uma coleção ser recalculado repetidamente, parece que isso pode ser especificado por meio de um parâmetro opcional e que o comportamento padrão pode fazer o contrário. Além disso, a vantagem de velocidade obtida com a execução adiada é reduzida no tempo necessário para recalcular continuamente os mesmos resultados. Finalmente, este é um bloco confuso para aqueles que são novos no LINQ e pode levar a erros sutis no programa de qualquer um.
Que vantagem há para isso e por que a Microsoft tomou essa decisão aparentemente muito deliberada?
return listOfNames.Select(x => new Record(Guid.NewGuid(), x)).ToList();
Isso fornece sua "cópia em cache". Problema resolvido.