2011-02-27 94 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成本

從一個可測試性來看,懶惰已經進行了測試並被證明是神器。

但是,它有一個非常輕微的開銷,在我看來,比其他選項