2011-02-27 70 views
47

在.NET 4中,还可以使用System.Lazy<T>类写入以下带有缓存属性的片段。我测量了两种方法的性能,并且几乎相同。对于我为什么应该使用一种优势,有没有什么真正的好处或魔力?缓存属性vs懒惰<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; 
     } 
    } 
} 

懒<牛逼>

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

通过使用'懒惰'你是'Lazy'写自己的实现。 (当然,这是一个很好的方法。) – BoltClock 2011-02-27 17:49:42

+0

有趣的是,我倾向于说它代码少,可读性好,但是你的例子证明情况并非如此。但是,再次,我已经有一个'Property '类来支持支持这个和更常见的后台字段行为的字段。 – 2011-02-27 17:49:58

+0

懒惰允许线程安全 – Tsayper 2015-08-07 06:29:26

回答

68

我会使用一般Lazy<T>

  • 它是线程安全的(可能不是在这种情况下的问题,但会在其他国家)
  • 这使得它很明显这是怎么回事只是由命名
  • 它允许空值是一个有效的值

请注意,你不使用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>字段不是只读) - 但我很少发现这很重要。

+1

在什么情况下会使用懒惰的问题? – user256034 2011-02-27 17:52:34

+14

@ user256034:当你不使用.NET 4时:) – 2011-02-27 17:53:52

+0

谢谢!在你的名单中的3点正是我正在寻找;) – 2011-02-27 18:14:29

1

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

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

2

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

7

使用Lazy<T>,因为它表达了你在做什么 - 懒加载。

此外,它保持你的财产非常干净,线程安全。

-1

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

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

+1

-1,OP的替代方案是相同的,即如果该属性永远不会被调用,那么该列表永远不会被实例化。从这个意义上说,他们都是“懒惰”的。 – tsemer 2015-12-31 10:18:37

4

通常,不使用懒惰的唯一原因是将该变量重置为空,因此下一次访问会导致它再次加载。懒惰没有重置,你需要重新从头开始懒惰。

+0

看到这个答案http://stackoverflow.com/questions/5961252/reset-system-lazy/6255398#6255398 – Olmo 2011-06-06 16:59:46

+0

好点!恕我直言,这与@ JonSkeet的答案相结合是完整的答案。 – tsemer 2015-12-31 10:20:13

0

懒具有一定的同步化开销来提供线程安全的,而缓存的属性由CLR方式在任何其他代码initiliazed,你不需要支付synronization成本

从一个可测试性来看,懒惰已经进行了测试并被证明是神器。

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