我找到了这篇关于懒惰的文章:c# 4.0中的懒惰-懒惰

使用Lazy对象获得最佳性能的最佳实践是什么? 谁能给我指出在实际应用中的实际用途?换句话说,我应该什么时候使用它?


当前回答

再扩展一下Matthew的例子:

public sealed class Singleton
{
    // Because Singleton's constructor is private, we must explicitly
    // give the Lazy<Singleton> a delegate for creating the Singleton.
    private static readonly Lazy<Singleton> instanceHolder =
        new Lazy<Singleton>(() => new Singleton());

    private Singleton()
    {
        ...
    }

    public static Singleton Instance
    {
        get { return instanceHolder.Value; }
    }
}

在Lazy成为框架的一部分之前,我们会这样做:

private static object lockingObject = new object();
public static LazySample InstanceCreation()
{
    if(lazilyInitObject == null)
    {
         lock (lockingObject)
         {
              if(lazilyInitObject == null)
              {
                   lazilyInitObject = new LazySample ();
              }
         }
    }
    return lazilyInitObject ;
}

其他回答

再扩展一下Matthew的例子:

public sealed class Singleton
{
    // Because Singleton's constructor is private, we must explicitly
    // give the Lazy<Singleton> a delegate for creating the Singleton.
    private static readonly Lazy<Singleton> instanceHolder =
        new Lazy<Singleton>(() => new Singleton());

    private Singleton()
    {
        ...
    }

    public static Singleton Instance
    {
        get { return instanceHolder.Value; }
    }
}

在Lazy成为框架的一部分之前,我们会这样做:

private static object lockingObject = new object();
public static LazySample InstanceCreation()
{
    if(lazilyInitObject == null)
    {
         lock (lockingObject)
         {
              if(lazilyInitObject == null)
              {
                   lazilyInitObject = new LazySample ();
              }
         }
    }
    return lazilyInitObject ;
}

在现实世界中,延迟加载派上用场的一个很好的例子是ORM(对象关系映射器),如实体框架和NHibernate。

假设您有一个实体Customer,它具有Name、PhoneNumber和Orders的属性。Name和PhoneNumber是常规字符串,而Orders是一个导航属性,返回客户曾经下过的每个订单的列表。

您可能经常想要查看所有客户的信息,并获得他们的姓名和电话号码,以便给他们打电话。这是一个非常快速和简单的任务,但是想象一下,如果每次创建一个客户,它都会自动执行一个复杂的连接来返回数千个订单。最糟糕的是,你甚至不会使用订单,所以这完全是浪费资源!

这是延迟加载的理想位置,因为如果Order属性是惰性的,它将不会获取所有客户的订单,除非您确实需要它们。您可以枚举Customer对象,只获取它们的Name和Phone Number,而Order属性则耐心地处于休眠状态,以便在需要时使用。

你应该尽量避免使用单例,但如果你确实需要,Lazy<T>使实现Lazy,线程安全的单例变得容易:

public sealed class Singleton
{
    // Because Singleton's constructor is private, we must explicitly
    // give the Lazy<Singleton> a delegate for creating the Singleton.
    static readonly Lazy<Singleton> instanceHolder =
        new Lazy<Singleton>(() => new Singleton());

    Singleton()
    {
        // Explicit private constructor to prevent default public constructor.
        ...
    }

    public static Singleton Instance => instanceHolder.Value;
}

从MSDN:

使用Lazy实例可以延迟大型或资源密集型对象的创建或资源密集型任务的执行,特别是当此类创建或执行在程序的生命周期内可能不会发生时。

除了James Michael Hare的回答,Lazy还提供了线程安全的值初始化。看一下LazyThreadSafetyMode枚举MSDN条目,该条目描述了该类的各种类型的线程安全模式。

当你想在第一次实际使用某个东西时实例化它时,通常会使用它。这将延迟创建它的成本,直到需要时,而不是总是产生成本。

通常,当对象可能被使用,也可能不被使用,并且构造它的成本不是微不足道时,这是可取的。