2010-10-27 111 views
63

在C#中,C#惰性加載自動屬性

有沒有辦法將一個自動屬性變成帶有指定默認值的延遲加載自動屬性?

從本質上講,我試圖把這個...

private string _SomeVariable 

public string SomeVariable 
{ 
    get 
    { 
      if(_SomeVariable == null) 
      { 
      _SomeVariable = SomeClass.IOnlyWantToCallYouOnce(); 
      } 

      return _SomeVariable; 
    } 
} 

到不同的東西,在那裏我可以指定默認的,它會自動處理剩下的...

[SetUsing(SomeClass.IOnlyWantToCallYouOnce())] 
public string SomeVariable {get; private set;} 
+0

@Gabe:注意,只有當它永遠不會ret urns null。 – RedFilter 2010-10-27 19:25:16

+0

我發現...它似乎是使用單例模式 – ctorx 2010-10-28 19:50:08

回答

80

不,沒有。自動實現的屬性僅用於實現最基本的屬性:帶getter和setter的後臺字段。它不支持這種類型的自定義。

但是你可以使用4.0 Lazy<T>類型來創建這個模式

private Lazy<string> _someVariable =new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce); 
public string SomeVariable { 
    get { return _someVariable.Value; } 
} 

此代碼將懶洋洋地計算_someVariable首次Value表達被稱爲價值。它只會被計算一次,並將緩存價值以供將來使用Value屬性

+1

實際上,它看起來像懶惰實現單例模式。這不是我的目標......我的目標是創建一個延遲加載的屬性,該屬性被懶惰地實例化,但隨着它所在的類的實例一起被處理。懶惰似乎沒有這樣的表現。 – ctorx 2010-10-28 19:12:24

+12

@ctorx懶惰與單身模式無關。它正是你想要它做的。 – Stijn 2013-02-20 07:15:39

+4

請注意,在您的示例中,「SomeClass.IOnlyWantToCallYouOnce」必須是靜態的,才能與字段初始值設定項一起使用。 – 2016-12-01 14:11:03

2

我不不認爲這是純粹的C#可能。但你可以使用IL重寫器,如PostSharp。例如,它允許您根據屬性在函數之前和之後添加處理程序。

5

不是這樣,屬性的參數必須是常數值,您不能調用代碼(即使是靜態代碼)。

然而,您可能能夠使用PostSharp的方面來實現某些功能。

檢查出來:

PostSharp

17

也許是最簡潔的,你可以得到的是使用空合併運算符:

get { return _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce()); } 
+4

在'IOnlyWantToCallYouOnce'返回'null'的情況下,它會多次調用它。 – JaredPar 2010-10-27 19:26:08

+6

使用空合併運算符時,上述示例將失敗。正確的語法是:'_SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce());' - 注意圍繞設置'_SomeVariable'添加括號,如果它爲空。 – 2012-10-22 16:49:51

4

下面是我實現的解決您的問題。基本上這個想法是一個屬性,它將在第一次訪問時由函數設置,隨後的訪問將產生與第一次訪問相同的返回值。

public class LazyProperty<T> 
{ 
    bool _initialized = false; 
    T _result; 

    public T Value(Func<T> fn) 
    { 
     if (!_initialized) 
     { 
      _result = fn(); 
      _initialized = true; 
     } 
     return _result; 
    } 
} 

然後使用:

LazyProperty<Color> _eyeColor = new LazyProperty<Color>(); 
public Color EyeColor 
{ 
    get 
    { 
     return _eyeColor.Value(() => SomeCPUHungryMethod()); 
    } 
} 

當然還有各地的傳遞函數指針的開銷,但它的工作,我和比我跑沒有注意到的開銷太大該方法一遍又一遍。

+0

將該函數賦予構造函數會更有意義嗎?這樣你就不會每次都以內聯的方式創建它,而且你可以在第一次使用它之後進行處置。 – 2014-01-15 02:57:08

+0

@ lund.mikkel是的,那也可以。可能是兩種方法的用例。 – deepee1 2014-01-15 17:07:49

+5

如果您將函數傳遞給構造函數,就像.Net的Lazy類一樣,那麼傳入的函數必須是靜態的,我知道這在許多情況下都不適合我的設計。 – crunchy 2014-05-09 18:16:25

8

有一個在C#中的新功能,6名爲Expression Bodied Auto-Properties,它允許你把它寫一點清潔劑:

public class SomeClass 
{ 
    private Lazy<string> _someVariable = new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce); 

    public string SomeVariable 
    { 
     get { return _someVariable.Value; } 
    } 
} 

目前可以寫爲:

public class SomeClass 
{ 
    private Lazy<string> _someVariable = new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce); 

    public string SomeVariable => _someVariable.Value; 
} 
+0

在上一節的代碼,初始化實際上並不是懶惰的。在每次實例化類時,都會調用「IOnlyWantToCallYouOnce」。 – 2016-07-03 14:51:51

+0

@TomBlodget謝謝,你是對的 – 2016-08-18 14:56:47

+0

因此換句話說這不是懶加載? – Zapnologica 2017-01-30 08:40:39

0

https://github.com/bcuff/AutoLazy使用Fody到給你這樣的東西

public class MyClass 
{ 
    // This would work as a method, e.g. GetSettings(), as well. 
    [Lazy] 
    public static Settings Settings 
    { 
     get 
     { 
      using (var fs = File.Open("settings.xml", FileMode.Open)) 
      { 
       var serializer = new XmlSerializer(typeof(Settings)); 
       return (Settings)serializer.Deserialize(fs); 
      } 
     } 
    } 

    [Lazy] 
    public static Settings GetSettingsFile(string fileName) 
    { 
     using (var fs = File.Open(fileName, FileMode.Open)) 
     { 
      var serializer = new XmlSerializer(typeof(Settings)); 
      return (Settings)serializer.Deserialize(fs); 
     } 
    } 
}