繁体   English   中英

缓存属性vs Lazy <T>

[英]Cached property vs Lazy<T>

在.NET 4中,还可以使用System.Lazy<T>类编写具有缓存属性的以下代码段。 我测量了两种方法的性能,它几乎是一样的。 对于为什么我应该使用一个而不是另一个,是否有任何真正的好处或魔力?

缓存属性

public static class Brushes
{
    private static LinearGradientBrush _myBrush;

    public static LinearGradientBrush MyBrush
    {
        get
        {
            if (_myBrush == null)
            {
                var linearGradientBrush = new LinearGradientBrush { ...};
                linearGradientBrush.GradientStops.Add( ... );
                linearGradientBrush.GradientStops.Add( ... );

                _myBrush = linearGradientBrush;
            }

            return _myBrush;
        }
    }
}

懒惰<T>

public static class Brushes
{
    private static readonly Lazy<LinearGradientBrush> _myBrush =
        new Lazy<LinearGradientBrush>(() =>
            {
                var linearGradientBrush = new LinearGradientBrush { ...};
                linearGradientBrush.GradientStops.Add( ... );
                linearGradientBrush.GradientStops.Add( ... );

                return linearGradientBrush;
            }
        );

    public static LinearGradientBrush MyBrush
    {
        get { return _myBrush.Value; }
    }
}

我会一般使用Lazy<T>

  • 它是线程安全的(在这种情况下可能不是问题,但在其他情况下可能会出现问题)
  • 它显而易见的是,这个名字正在发生什么
  • 它允许null为有效值

请注意,您不必使用lambda表达式的委托。 例如,这是一种可能稍微清洁的方法:

public static class Brushes
{
    private static readonly Lazy<LinearGradientBrush> _myBrush =
        new Lazy<LinearGradientBrush>(CreateMyBrush);

    private static LinearGradientBrush CreateMyBrush()
    {
        var linearGradientBrush = new LinearGradientBrush { ...};
        linearGradientBrush.GradientStops.Add( ... );
        linearGradientBrush.GradientStops.Add( ... );

        return linearGradientBrush;
    }

    public static LinearGradientBrush MyBrush
    {
        get { return _myBrush.Value; }
    }
}

当创建过程变得复杂时,这尤其方便。请注意,通过它的外观,您可以在创建代码中使用GradientStops的集合初始值设定项。

另一个选择是不要懒惰,当然......除非你的类中有几个这样的属性而你只想逐个创建相关的对象,你可以依赖懒惰的类初始化的情况。

正如DoubleDown的回答所指出的,没有办法重置它来强制重新计算(除非你让Lazy<T>字段不是只读) - 但我很少发现这很重要。

使用Lazy<T> ,因为它表达了你正在做的事情 - 延迟加载。

此外,它保持您的财产非常干净,并且是线程安全的。

通常,不使用lazy的唯一原因是将变量重置为null,以便下一次访问使其再次加载。 懒惰没有重置,你需要从头开始重新创建懒惰。

Lazy<T>将正确处理并发场景(如果传入正确的LazyThreadSafetyMode ),而您的示例没有任何线程安全检查。

Lazy<T>更简单 - 它清楚地表达了代码的意图。
它也是线程安全的。

请注意,如果您实际上在多个线程上使用它,则需要将其设置为[ThreadStatic] ; GDI +对象不能跨线程共享。

Lazy有一些同步化开销来提供线程安全性,而缓存属性在任何其他代码之前通过CLR方式初始化,并且您不需要支付同步成本

从可测试性的角度来看,Lazy经过了充分的测试和验证。

但是,在我看来,它有一个非常轻微的开销,而不是其他选择

好吧,如果你的性能大致相同,那么在缓存版本上使用Lazy<T>的唯一原因是,如果你不确定用户是否真的要加载该属性。

Lazy<T>的要点是等到用户需要资源,然后及时在该实例创建它。 如果他们总是需要资源,那么使用Lazy<T>是没有意义的,除非你需要一些其他目的,比如它是线程安全的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM