简体   繁体   English

缓存属性vs Lazy <T>

[英]Cached property vs Lazy<T>

In .NET 4 the following snippet with a cached property can also be written using the System.Lazy<T> class. 在.NET 4中,还可以使用System.Lazy<T>类编写具有缓存属性的以下代码段。 I measured the performance of both approaches and it's pretty much the same. 我测量了两种方法的性能,它几乎是一样的。 Is there any real benefit or magic for why I should use one over the other? 对于为什么我应该使用一个而不是另一个,是否有任何真正的好处或魔力?

Cached Property 缓存属性

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;
        }
    }
}

Lazy<T> 懒惰<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; }
    }
}

I would use Lazy<T> in general: 我会一般使用Lazy<T>

  • It's thread-safe (may not be an issue in this case, but would be in others) 它是线程安全的(在这种情况下可能不是问题,但在其他情况下可能会出现问题)
  • It makes it obvious what's going on just by the name 它显而易见的是,这个名字正在发生什么
  • It allows null to be a valid value 它允许null为有效值

Note that you don't have to use a lambda expression for the delegate. 请注意,您不必使用lambda表达式的委托。 For example, here's an approach which may be slightly cleaner: 例如,这是一种可能稍微清洁的方法:

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; }
    }
}

This is particularly handy when the creation process gets complicated with loops etc. Note that by the looks of it, you could use a collection initializer for GradientStops in your creation code. 当创建过程变得复杂时,这尤其方便。请注意,通过它的外观,您可以在创建代码中使用GradientStops的集合初始值设定项。

Another option is not to do this lazily, of course... unless you have several such properties in your class and you only want to create the relevant objects on a one-by-one basis, you could rely on lazy class initialization for many situations. 另一个选择是不要懒惰,当然......除非你的类中有几个这样的属性而你只想逐个创建相关的对象,你可以依赖懒惰的类初始化的情况。

As noted in DoubleDown's answer, there's no way of resetting this to force recomputation (unless you make the Lazy<T> field not readonly) - but I've very rarely found that to be important. 正如DoubleDown的回答所指出的,没有办法重置它来强制重新计算(除非你让Lazy<T>字段不是只读) - 但我很少发现这很重要。

Use Lazy<T> , as it expresses exactly what you are doing - lazy loading. 使用Lazy<T> ,因为它表达了你正在做的事情 - 延迟加载。

In addition, it keeps your property very clean and is thread safe. 此外,它保持您的财产非常干净,并且是线程安全的。

Typically the only reason to not use lazy is to reset the variable to null so the next access causes it to load again. 通常,不使用lazy的唯一原因是将变量重置为null,以便下一次访问使其再次加载。 Lazy has no reset and you'd need to recreate the lazy from scratch. 懒惰没有重置,你需要从头开始重新创建懒惰。

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

The Lazy<T> is simpler—it clearly expresses the intent of the code. Lazy<T>更简单 - 它清楚地表达了代码的意图。
It's also thread safe. 它也是线程安全的。

Note that if you're actually using this on multiple threads, you need to make it [ThreadStatic] ; 请注意,如果您实际上在多个线程上使用它,则需要将其设置为[ThreadStatic] ; GDI+ objects cannot be shared across threads. GDI +对象不能跨线程共享。

Lazy has some syncronization overhead to provide thread-safety whereas cached property is initiliazed by CLR way before any other code and you do not need to pay synronization cost Lazy有一些同步化开销来提供线程安全性,而缓存属性在任何其他代码之前通过CLR方式初始化,并且您不需要支付同步成本

From a testability point of view, Lazy is well tested and proven artifact. 从可测试性的角度来看,Lazy经过了充分的测试和验证。

However, it has a very slight overhead, in my opinion, over other option 但是,在我看来,它有一个非常轻微的开销,而不是其他选择

Well if your performance is about the same then the only reason to use Lazy<T> over the cached version would be if you aren't sure if the user is actually going to load the property. 好吧,如果你的性能大致相同,那么在缓存版本上使用Lazy<T>的唯一原因是,如果你不确定用户是否真的要加载该属性。

The point of Lazy<T> is to wait until the user needs the resource and then create it at that instance in time. Lazy<T>的要点是等到用户需要资源,然后及时在该实例创建它。 If they are always going to need to resource then there is no point in using Lazy<T> , unless you need some of it's other purposes such as it being thread safe. 如果他们总是需要资源,那么使用Lazy<T>是没有意义的,除非你需要一些其他目的,比如它是线程安全的。

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

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