Lazy<T>为什么会得到Func<T>?

4
有人能用简单的话解释一下,为什么C#中的Lazy需要获取Func吗?
public Lazy (Func<T> valueFactory);

我知道有时你需要一个函数来执行某些高级的init()操作,但是很多情况下我发现自己写了一个单例或者其他简单的东西,只需创建该类的新实例。就像Jon Skeet的书中所示。 http://csharpindepth.com/Articles/General/Singleton.aspx 我认为这种语法非常恼人。
谢谢!
private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());

3
您希望语法看起来像什么?Lazy<T>的要点是,只有在首次访问lazy时才执行new Singleton()。如果语法是new Lazy<Singleton>(new Singleton());,则实例将立即创建。您需要一个在首次访问lazy时执行的Func<T> - René Vogt
1
请查看以下网址以了解.NET 4中的延迟初始化:https://dev59.com/emw15IYBdhLWcg3wv-RM - Rui Jarimba
4个回答

7
你需要一个函数,因为如果你能做到这一点:
var Lazy<Foo> = new Lazy<Foo>(new Foo());

你已经在实例化Foo,而你并不想这样做,否则你就不需要使用Lazy<T>

Func<T>持有Foo的初始化器,但只有当你访问Lazy<T>Value时才进行初始化。


6

如果没有初始化函数,你无法让Lazy正常工作。这就是它确保对象创建的逻辑已存在但尚未调用的方法。

考虑下面的例子:

new Lazy<Singleton>(new Singleton());

这已经实例化了一个新的Singleton。懒加载现在已经没有用处了。该函数允许Lazy<T>在将来的任何时间构造对象。

Func<T>的另一个优点是它不需要实例化一个新对象。它可以是任何其他东西。它可以是多行语句、获取其他东西等。

我可以提出的一个优化是,new Lazy<T>()将使用T上的new(),这样就不需要调用构造函数了。然而,这在当前语法下是不可能的,但它可以使用静态工厂方法实现。

像这样(是的,基本上做的就是你现在做的事情,只是把它藏在核心中):

public static class LazyDefault
{
    public static Lazy<TNew> New<TNew>() where TNew : new()
    {
        return new Lazy<TNew>(() => new TNew());
    }
}

或者像CodeCaster建议的那样使用派生类:

public class SuperLazy<T> : Lazy<T>
    where T : new()
{
    public SuperLazy()
         : base(() => new T())
    {
    }
}

"new Lazy<T>()会使用T上的new()方法" - https://www.ideone.com/ttOhIk - 但你基本上只是写了同样的内容。 - CodeCaster

1
你提供给 Lazy<T> 构造函数的内容被称为 thunkWikipedia):
在计算机编程中,thunk 是用于将附加计算注入到另一个子例程中的子例程。Thunk 主要用于延迟计算,直到需要其结果,或者在其他子例程的开头或结尾插入操作。它们在编译器代码生成和模块化编程中有各种其他应用。
也就是说,惰性求值 的核心是将整个待评估的内容延迟到真正需要它的时候再进行评估。
如果你觉得必须显式地提供 Func<T> 很烦人,可以通过以下方式简化:
public static class Lazy 
{
     public static Lazy<T> Of<T>()
            where T : class, new() => new Lazy<T>(() => new T())
}


var lazyFoo = Lazy.Of<Foo>()

1

Lazy 需要一个 Func 来实际初始化内部值。使用 Lazy 的整个目的是仅在需要时初始化值。因此,当需要时,应该有一种方式让 Lazy 实际初始化值,这就是 Func 的作用。我看不到除了传递初始化函数之外实现类似 Lazy 的其他方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接