Đây là một cạm bẫy được biết đến đối với những người bị ướt chân khi sử dụng 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;
}
}
}
Điều này sẽ in "Sai", vì với mỗi tên được cung cấp để tạo bộ sưu tập gốc, hàm select sẽ tiếp tục được đánh giá lại và Record
đối tượng kết quả được tạo lại. Để khắc phục điều này, một cuộc gọi đơn giản ToList
có thể được thêm vào cuối GenerateRecords
.
Microsoft đã hy vọng đạt được lợi thế gì khi thực hiện theo cách này?
Tại sao việc thực hiện không chỉ đơn giản là lưu trữ kết quả một mảng nội bộ? Một phần cụ thể của những gì đang xảy ra có thể bị hoãn thực thi, nhưng điều đó vẫn có thể được thực hiện mà không có hành vi này.
Khi một thành viên nhất định của bộ sưu tập được LINQ trả về đã được đánh giá, lợi thế nào được cung cấp bằng cách không giữ tham chiếu / bản sao nội bộ, mà thay vào đó tính toán lại kết quả tương tự, như một hành vi mặc định?
Trong các tình huống có nhu cầu đặc biệt về logic cho cùng một thành viên của bộ sưu tập được tính toán lại nhiều lần, có vẻ như điều đó có thể được chỉ định thông qua một tham số tùy chọn và hành vi mặc định có thể làm khác. Ngoài ra, lợi thế về tốc độ đạt được khi thực hiện hoãn lại cuối cùng bị cắt giảm theo thời gian cần thiết để liên tục tính toán lại các kết quả tương tự. Cuối cùng, đây là khối khó hiểu đối với những người mới sử dụng LINQ và nó có thể dẫn đến các lỗi tinh vi trong chương trình của bất kỳ ai.
Lợi thế nào cho điều này, và tại sao Microsoft lại đưa ra quyết định dường như rất có chủ ý này?
return listOfNames.Select(x => new Record(Guid.NewGuid(), x)).ToList();
Điều đó cung cấp cho bạn "bản sao lưu trữ." Vấn đề được giải quyết.