2010-10-27 6 views
63

सी # में,सी # लेज़ी लोडेड स्वत: गुण

वहाँ एक रास्ता एक निर्धारित डिफ़ॉल्ट मान के साथ एक आलसी लोड स्वचालित संपत्ति में एक स्वत: संपत्ति चालू करने के लिए है?

अनिवार्य रूप से, मैं कुछ अलग है, जहां मैं डिफ़ॉल्ट निर्दिष्ट कर सकते हैं में इस बारी करने की कोशिश कर रहा हूँ ...

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 कुछ इस तरह देते हैं नल शून्य – RedFilter

+0

मैंने पाया कि ... ऐसा लगता है कि सिंगलटन पैटर्न – ctorx

उत्तर

80

कोई नहीं है। स्वत: कार्यान्वित गुण केवल गुणों के सबसे बुनियादी को लागू करने के लिए कार्य करते हैं: गेटटर और सेटर के साथ बैकिंग फ़ील्ड। यह इस प्रकार के अनुकूलन का समर्थन नहीं करता है।

आप इस पैटर्न

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

इस कोड lazily _someVariable पहली बार Value अभिव्यक्ति कहा जाता है के मूल्य की गणना करेगा बनाने के लिए 4.0 Lazy<T> प्रकार का उपयोग कर सकते हैं हालांकि। इसकी गणना केवल एक बार की जाएगी और Value संपत्ति के भविष्य के उपयोग के लिए मूल्य कैश करेगा

+1

असल में, यह मुझे लगता है कि आलसी सिंगलटन पैटर्न को लागू करता है। यह मेरा लक्ष्य नहीं है ... मेरा लक्ष्य एक आलसी लोड संपत्ति है जो आलसी रूप से तत्काल है लेकिन जिस वर्ग में वह रहता है उसके उदाहरण के साथ निपटान किया जाता है। आलसी ऐसा नहीं कर रहा प्रतीत होता है। – ctorx

+12

@क्टरx आलसी के सिंगलटन पैटर्न से कोई लेना देना नहीं है। यह वही करता है जो आप करना चाहते हैं। – Stijn

+4

नोट, आपके उदाहरण में 'SomeClass.IOnlyWantToCallYouOnce' फ़ील्ड प्रारंभकर्ता के साथ उपयोग करने के लिए स्थैतिक होना चाहिए। –

2

मैं डॉन यह नहीं लगता कि शुद्ध सी # के साथ यह संभव है। लेकिन आप इसे PostSharp जैसे आईएल रीराइटर का उपयोग करके कर सकते हैं। उदाहरण के लिए यह आपको विशेषताओं के आधार पर कार्यों के पहले और बाद में हैंडलर जोड़ने की अनुमति देता है।

5

ऐसा नहीं है, गुणों के लिए पैरामीटर मान में स्थिर होना चाहिए, आप कोड (यहां तक ​​कि स्थिर कोड) भी नहीं कॉल कर सकते हैं।

हालांकि आप पोस्टशर्प के पहलुओं के साथ कुछ लागू करने में सक्षम हो सकते हैं।

उन पर नज़र डालें:

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

शायद सबसे संक्षिप्त आप प्राप्त कर सकते हैं अशक्त-कोलेसिंग ऑपरेटर का प्रयोग है। असल में विचार एक ऐसी संपत्ति है जो किसी फ़ंक्शन द्वारा पहली पहुंच पर सेट की जाएगी और बाद में पहुंच पहले के समान वापसी मूल्य प्रदान करेगी।

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

समारोह सूचक के आसपास गुजर की भूमि के ऊपर निश्चित रूप से नहीं है, लेकिन यह मेरे लिए काम करता है और मैं चल रहा है की तुलना में सूचना नहीं बहुत ज्यादा भूमि के ऊपर विधि बार-बार।

+4

मामले में 'IOnlyWantToCallYouOnce'' शून्य 'लौटाता है, यह इसे एक से अधिक बार कॉल करेगा। – JaredPar

+6

नल-कोलेसिंग ऑपरेटर का उपयोग करते समय, उपर्युक्त उदाहरण विफल हो जाएगा। सही वाक्यविन्यास है: '_SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce()); '- शून्य होने पर' _SomeVariable' सेटिंग के आसपास कोष्ठक के अतिरिक्त को नोटिस करें। –

4

यहाँ अपने समस्या का हल के अपने कार्यान्वयन है:

PostSharp

+0

कन्स्ट्रक्टर को फ़ंक्शन देने के लिए और अधिक समझदारी नहीं होगी? इस तरह आप इसे हर बार इनलाइन नहीं बनायेंगे, और आप इसे पहली बार इस्तेमाल करने के बाद इसका निपटान कर सकते हैं। –

+0

@ lund.mikkel हाँ, यह भी काम करेगा। दोनों दृष्टिकोणों के लिए मामलों का उपयोग कर सकते हैं। – deepee1

+5

यदि आप कन्स्ट्रक्टर को फ़ंक्शन पास करते हैं, तो नेट की आलसी कक्षा की तरह, तो फ़ंक्शन में पारित फ़ंक्शन को स्थिर होना होगा, मुझे पता है कि यह कई मामलों में मेरे डिज़ाइन में फिट नहीं है। – crunchy

8

वहाँ सी # में एक नई सुविधा 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' निर्माण के दौरान बुलाया जाएगा। –

+0

@TomBlodget धन्यवाद, आप सही हैं –

+0

तो अन्य शब्दों में यह आलसी लोड नहीं है? – Zapnologica

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