C # आलसी लोड स्वचालित गुण


100

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

@ गैब: ध्यान दें कि कक्षा को केवल एक बार बुलाया जाएगा यदि वह कभी भी अशक्त नहीं लौटेगी।
RedFilter

मुझे पता चला कि ... यह सिंगलटन पैटर्न का उपयोग करता है
ctorx

जवाबों:


112

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

हालाँकि आप Lazy<T>इस पैटर्न को बनाने के लिए 4.0 प्रकार का उपयोग कर सकते हैं

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

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


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

19
@ctorx Lazy का सिंगलटन पैटर्न से कोई लेना-देना नहीं है। यह वही करता है जो आप करना चाहते हैं।
user247702

8
ध्यान दें, SomeClass.IOnlyWantToCallYouOnceआपके उदाहरण में फ़ील्ड इनिशलाइज़र के साथ उपयोग किया जाना स्थिर होना चाहिए।
rory.ap

बहुत बढ़िया जवाब। यदि आप कई आलसी गुणों की अपेक्षा करते हैं, तो एक विजुअल स्टूडियो स्निपेट के लिए मेरा उत्तर देखें।
जेफ्रील

40

संभवत: सबसे संक्षिप्त रूप से आप अशक्त-संचालक ऑपरेटर का उपयोग कर सकते हैं:

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

10
मामले में IOnlyWantToCallYouOnceरिटर्न nullइसे एक से अधिक बार कॉल करेगा।
JaredPar

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

यह सबसे अच्छा विकल्प है। पहले मैंने इस्तेमाल किया Lazy<>, लेकिन हमारे उद्देश्यों के लिए इसने बेहतर काम किया। लेटेस्ट C # के साथ इसे और भी संक्षिप्त लिखा जा सकता है। => _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce());कुछ जो पहली नजर से नहीं देख सकते हैं, वह यह है कि ऑपरेटर दाएं हाथ के ऑपरेंड का मूल्यांकन करता है और उसका परिणाम देता है
RunninglVlan

15

C # 6 में एक नई सुविधा है जिसे एक्सप्रेशन बोडीड ऑटो-प्रॉपर्टीज कहा जाता है , जो आपको इसे थोड़ा क्लीनर लिखने की अनुमति देता है:

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

कोड के अंतिम खंड में, आरंभीकरण वास्तव में आलसी नहीं है। IOnlyWantToCallYouOnceहर बार निर्माण के दौरान क्लास को तुरंत बताया जाता है।
टॉम ब्लोडेट

तो दूसरे पासवर्ड में यह आलसी लोड नहीं है?
जैपनीजोलिका

@Zapnologica मेरा पिछला जवाब थोड़ा गलत था लेकिन मैंने इसे अपडेट कर दिया। SomeVariableआलसी भरी हुई है।
अलेक्जेंडर डर्क

यह उत्तर एक्सप्रेशन बोडिड ऑटो-प्रॉपर्टीज के लिए एक पिच की तरह अधिक पढ़ता है।
छोटा एंडियन

@AbleArcher एक नई भाषा सुविधा को इंगित करता है जो अब एक पिच है?
अलेक्जेंडर डर्क

5

ऐसा नहीं है, विशेषताओं के लिए पैरामीटर मूल्य में स्थिर होना चाहिए, आप कोड (यहां तक ​​कि स्थिर कोड) को कॉल नहीं कर सकते।

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

उनकी जाँच करो:

PostSharp


5

यहाँ आपकी समस्या के समाधान का मेरा कार्यान्वयन है। मूल रूप से यह विचार एक संपत्ति है जिसे पहली बार में एक फ़ंक्शन द्वारा सेट किया जाएगा और बाद की एक्सेस पहले की तरह ही रिटर्न वैल्यू देगी।

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

बेशक फ़ंक्शन पॉइंटर को चारों ओर से गुजरने का ओवरहेड है, लेकिन यह मेरे लिए काम करता है और मैं बार-बार विधि को चलाने की तुलना में बहुत अधिक ओवरहेड को नोटिस नहीं करता हूं।


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

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

5
यदि आप फंक्शन को कंस्ट्रक्टर के पास भेजते हैं, बहुत कुछ .Net की लेज़ी क्लास की तरह, तो फंक्शन में पास होने के लिए स्टैटिक होना पड़ेगा, मुझे पता है कि यह कई मामलों में मेरे डिजाइन के अनुकूल नहीं है।
क्रंची

@ MikkelR.Lund कभी-कभी आप कंस्ट्रक्टर में कुछ कोड निष्पादित नहीं करना चाहते हैं, लेकिन केवल मांग पर (और बैकिंग फ़ील्ड के रूप में परिणाम कैश करें)
mamuesstack

3

मैं इस विचार का बहुत बड़ा प्रशंसक हूं, और मैं निम्नलिखित C # स्निपेट की पेशकश करना चाहूंगा जिसे मैंने proplazy.nippet कहा है (आप इसे आयात कर सकते हैं या इसे मानक फ़ोल्डर में पेस्ट कर सकते हैं जिसे आप स्निपेट प्रबंधक से प्राप्त कर सकते हैं)

यहाँ इसके उत्पादन का एक नमूना है:

private Lazy<int> myProperty = new Lazy<int>(()=>1);
public int MyProperty { get { return myProperty.Value; } }

यहाँ स्निपेट फ़ाइल सामग्री है: (proplazy.snippet के रूप में सहेजें)

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>proplazy</Title>
            <Shortcut>proplazy</Shortcut>
            <Description>Code snippet for property and backing field</Description>
            <Author>Microsoft Corporation</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>type</ID>
                    <ToolTip>Property type</ToolTip>
                    <Default>int</Default>
                </Literal>
                <Literal>
                    <ID>field</ID>
                    <ToolTip>The variable backing this property</ToolTip>
                    <Default>myVar</Default>
                </Literal>
                <Literal>
                    <ID>func</ID>
                    <ToolTip>The function providing the lazy value</ToolTip>
                </Literal>
                <Literal>
                    <ID>property</ID>
                    <ToolTip>Property name</ToolTip>
                    <Default>MyProperty</Default>
                </Literal>

            </Declarations>
            <Code Language="csharp"><![CDATA[private Lazy<$type$> $field$ = new Lazy<$type$>($func$);
            public $type$ $property$ { get{ return $field$.Value; } }
            $end$]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

2

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


2

ऑपरेटर ?? = C # 8.0 और बाद का उपयोग करके उपलब्ध है, इसलिए अब आप इसे और भी संक्षिप्त कर सकते हैं:

private string _someVariable;

public string SomeVariable => _someVariable ??= SomeClass.IOnlyWantToCallYouOnce();

1

मैंने इसे इस तरह किया:

public static class LazyCachableGetter
{
    private static ConditionalWeakTable<object, IDictionary<string, object>> Instances = new ConditionalWeakTable<object, IDictionary<string, object>>();
    public static R LazyValue<T, R>(this T obj, Func<R> factory, [CallerMemberName] string prop = "")
    {
        R result = default(R);
        if (!ReferenceEquals(obj, null))
        {
            if (!Instances.TryGetValue(obj, out var cache))
            {
                cache = new ConcurrentDictionary<string, object>();
                Instances.Add(obj, cache);

            }


            if (!cache.TryGetValue(prop, out var cached))
            {
                cache[prop] = (result = factory());
            }
            else
            {
                result = (R)cached;
            }

        }
        return result;
    }
}

और बाद में आप इसका उपयोग कर सकते हैं

       public virtual bool SomeProperty => this.LazyValue(() =>
    {
        return true; 
    });

मैं इस संदर्भ में "यह" कैसे उपयोग करूं?
रीरा

@ रीरा आपका क्या मतलब है? बस नियमित संपत्ति की तरह। उदा public ISet<String> RegularProperty {get;set} public string CalculatedProperty => this.LazyValue(() => { return string.Join(",", RegularProperty.ToArray()); });
अलेक्जेंडर जुबान

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

0
[Serializable]
public class RaporImza
{
    private readonly Func<ReportConfig> _getReportLayout;
    public RaporImza(Func<ReportConfig> getReportLayout)
    {
        _getReportLayout = getReportLayout;
    }

    private ReportConfig _getReportLayoutResult;
    public ReportConfig GetReportLayoutResult => _getReportLayoutResult ?? (_getReportLayoutResult = _getReportLayout());

    public string ImzaAtanKisiAdi => GetReportLayoutResult.ReportSignatureName;

    public string ImzaAtanKisiUnvani => GetReportLayoutResult.ReportSignatureTitle;
    public byte[] Imza => GetReportLayoutResult.ReportSignature;
}

और मैं बंदे की तरह कहता हूं

result.RaporBilgisi = new ExchangeProgramPersonAllDataModel.RaporImza(() => _reportConfigService.GetReportLayout(documentTypeId));

1
हालांकि यह लेखकों के सवाल का जवाब दे सकता है, लेकिन इसमें कुछ स्पष्ट शब्दों और प्रलेखन के लिंक का अभाव है। इसके आसपास कुछ वाक्यांशों के बिना रॉ कोड स्निपेट्स बहुत उपयोगी नहीं हैं। आप यह भी पा सकते हैं कि कैसे एक अच्छा उत्तर लिखने में बहुत मददगार है। कृपया अपना उत्तर संपादित करें।
नरक

0

यदि आप आलसी आरंभीकरण के दौरान एक कंस्ट्रक्टर का उपयोग करते हैं, तो निम्नलिखित एक्सटेंशन भी सहायक हो सकते हैं

public static partial class New
{
    public static T Lazy<T>(ref T o) where T : class, new() => o ?? (o = new T());
    public static T Lazy<T>(ref T o, params object[] args) where T : class, new() =>
            o ?? (o = (T) Activator.CreateInstance(typeof(T), args));
}

प्रयोग

    private Dictionary<string, object> _cache;

    public Dictionary<string, object> Cache => New.Lazy(ref _cache);

                    /* _cache ?? (_cache = new Dictionary<string, object>()); */

1
क्या आपके हेल्पर को इस्तेमाल करने का कोई फायदा है LazyInitializer.EnsureInitialized()? क्योंकि जो मैं बता सकता हूं, उससे ऊपर की कार्यक्षमता के अलावा, LazyInitializerत्रुटि हैंडलिंग के साथ-साथ सिंक कार्यक्षमता प्रदान करता है। LazyInitializer स्रोत कोड
semaj1919
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.