强制创建Lazy<T>对象

问题描述 投票:0回答:4

我收到了一系列

Lazy<T>
物品。然后我想一口气强行‘创造’它们。

void Test(IEnumerable<Lazy<MailMessage>> items){
}

通常,对于

Lazy<T>
项,在访问其成员之一之前,不会创建所包含的对象。

鉴于没有

ForceCreate()
方法(或类似方法),我被迫执行以下操作:

var createdItems = items
    .Where(a => a.Value != null && a.Value.ToString() != null)
    .Select(a => a.Value);

这是使用

ToString()
来强制创建每个项目。

有没有更简洁的方法来强制创建所有项目?

c# lazy-loading lazy-initialization
4个回答
7
投票

获取所有延迟初始化值的列表:

var created = items.Select(c => c.Value).ToList();

3
投票

您需要两件事来创建所有惰性项目,您需要枚举所有项目(但不一定保留它们),并且您需要使用

Value
属性来创建项目。

items.All(x => x.Value != null);

All
方法需要查看所有值来确定结果,因此这将导致枚举所有项目(无论集合的实际类型是什么),并且在每个项目上使用
Value
属性将导致它来创建它的对象。 (
!= null
部分只是为了设置一个让
All
方法满意的值。)


1
投票

因为没有 ForceCreate() 方法(或类似的方法)

您始终可以为此在

ForceCreate()
上创建一个
Lazy<T>
扩展方法:

public static class LazyExtensions
{
    public static Lazy<T> ForceCreate<T>(this Lazy<T> lazy)
    {
        if (lazy == null) throw new ArgumentNullException(nameof(lazy));

        _ = lazy.Value;
        return lazy;
    }
}

...伴随着

ForEach
上的
IEnumerable<T>
扩展方法:

public static class EnumerableExtensions
{
    public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
    {
        if (enumerable == null) throw new ArgumentNullException(nameof(enumerable));
        if (action == null) throw new ArgumentNullException(nameof(action));            

        foreach (var item in enumerable)
        {
            action(item);
        }
    }
}

通过组合这两种扩展方法,您可以一次性强制创建它们:

items.ForEach(x => x.ForceCreate());

1
投票
foreach (var x in lazyItems)
{
    _ = x.Value;
}

与其他一些解决方案相比的优点包括:

  • 不会为输出集合额外分配 O(n) 内存。
  • 如果遇到空值,不停止创建值。
  • 避免由于 LINQ 延迟执行而导致值是否创建的任何混淆。
© www.soinside.com 2019 - 2024. All rights reserved.