LasyList <T>仅适用于IQueryable<T>源。它是IList<T>的实现,通过使用来自指定 IQueryable<T> 的所有结果填充私有列表来工作。首次访问任何 IList<T> 成员时会进行初始化。
示例用法是
var myList = new LazyList(products.Where(p => p.Name.StartsWith("T"));
//initialization occurs here
Console.Write(myList.Count);
System.Lazy<T>类适用于任何类型,并且不限于 IQueryable<T>。延迟初始化在第一次访问Lazy<T>.Value属性时发生。
示例用法是
var lazyString = new Lazy(() => "Hello world");
//initialization occurs here
Console.Write(lazyString.Value);
我们可以重写 LazyList<T> 示例以使用 Lazy<T>,如下所示:
var myList = new Lazy(() => products.Where(p => p.Name.StartsWith("T").ToList());
//initialization occurs here
Console.Write(myList.Value.Count);
简而言之: LazyList<T> 仅适用于 IQueryable<T>,Lazy<T> 适用于任何类型。
LazyList<T> 适用于当您希望 IQueryable<T> 的结果作为 List<T> 的特定用例,但您不希望在使用它之前进行评估。
更新以回答扩展问题:
如果我想将 IQueryable 作为 List<T> 进行操作,您会推荐其中一个吗?我假设由于 Lazy<T> 现在在框架中,对于未来的支持和可维护性来说这是一个更安全的选择?
我个人也不会使用。如果您有 IQueryable,我会将其保留为 IQueryable,以最大限度地提高您的灵活性。通过保留 IQueryable,您仍然可以访问 LINQ to SQL 的查询理解(只要上下文仍然存在)。
例如,如果您在 IQueryable 上调用 .ToList() ,您是在要求 LINQ to SQL 从目标表中选择所有列并混合所有结果(这可能非常昂贵,特别是如果您有数千个结果)。这将被翻译成类似“SELECT * FROM MyTable”的内容。
如果您在 IQueryable 上调用 .Count(),则您要求 LINQ to SQL 仅获取结果数,这将被转换为“SELECT COUNT(*) FROM MyTable”之类的内容。这样做比将所有结果水合然后计算它们更有效,特别是如果您只对数字感兴趣!
通过在 IQueryable LINQ to SQL 上使用 .Where() 会将您的条件添加到 SQL 查询中的 WHERE 子句中。这意味着您只会从您感兴趣的 SQL 中提取数据,而不是混合您无意使用的结果。
您会看到,通过保留 IQueryable,您可以让事情变得更加灵活。在大多数情况下,它会给您带来比对整个结果集进行水合更好的性能。
如果我想使用强类型而不是匿名 (var) 类型,以下语句在功能上是否等效?
Lazy<List<Product>> products = new Lazy<List<Product>>();
LazyList<Product> products = new LazyList<Product>();
我认为您将匿名输入与隐式输入混淆了。使用 var 关键字声明的变量被隐式类型化以匹配分配给它的类型。它是强类型的,因此在初始分配后无法更改。
这两个语句在功能上并不等效。LazyList<Product> 是 IList<Product>,而 Lazy<List<Product>> 是包含 List<Product> 的包装器。因为您对在惰性评估列表上进行操作特别感兴趣,所以我想说 LazyList可能更适合您的目的。
你应该问问自己是否真的需要一份实际的产品清单。如果没有令人信服的理由拥有一个实际的列表,我会坚持使用 IQueryable。