अन्य उत्तरों ने बहुत स्पष्टीकरण दिया है कि एक वैकल्पिक पैरामीटर एक गतिशील अभिव्यक्ति क्यों नहीं हो सकता है। लेकिन, पुनरावृत्ति करने के लिए, डिफ़ॉल्ट पैरामीटर संकलित समय स्थिरांक की तरह व्यवहार करते हैं। इसका मतलब है कि संकलक को उनका मूल्यांकन करने और एक उत्तर के साथ आने में सक्षम होना चाहिए। कुछ लोग हैं जो निरंतर घोषणाओं का सामना करते समय गतिशील अभिव्यक्तियों का मूल्यांकन करने वाले कंपाइलर के लिए समर्थन जोड़ना चाहते हैं - इस तरह की सुविधा अंकन विधियों "शुद्ध" से संबंधित होगी, लेकिन यह अभी वास्तविकता नहीं है और कभी भी नहीं हो सकती है।
इस तरह की विधि के लिए C # डिफ़ॉल्ट पैरामीटर का उपयोग करने का एक विकल्प यह होगा कि जिस पैटर्न का उपयोग किया गया है, उसका अनुकरण किया जाए XmlReaderSettings
। इस पैटर्न में, एक वर्ग को पैरामीटर रहित कंस्ट्रक्टर और सार्वजनिक रूप से लिखने योग्य गुणों के साथ परिभाषित करें। फिर इस प्रकार के ऑब्जेक्ट के साथ सभी विकल्पों को अपने तरीके से डिफॉल्ट के साथ बदलें। यहां तक कि इसके लिए एक डिफ़ॉल्ट निर्दिष्ट करके इस ऑब्जेक्ट को वैकल्पिक बनाएं null
। उदाहरण के लिए:
public class FooSettings
{
public TimeSpan Span { get; set; } = TimeSpan.FromSeconds(2);
// I imagine that if you had a heavyweight default
// thing you’d want to avoid instantiating it right away
// because the caller might override that parameter. So, be
// lazy! (Or just directly store a factory lambda with Func<IThing>).
Lazy<IThing> thing = new Lazy<IThing>(() => new FatThing());
public IThing Thing
{
get { return thing.Value; }
set { thing = new Lazy<IThing>(() => value); }
}
// Another cool thing about this pattern is that you can
// add additional optional parameters in the future without
// even breaking ABI.
//bool FutureThing { get; set; } = true;
// You can even run very complicated code to populate properties
// if you cannot use a property initialization expression.
//public FooSettings() { }
}
public class Bar
{
public void Foo(FooSettings settings = null)
{
// Allow the caller to use *all* the defaults easily.
settings = settings ?? new FooSettings();
Console.WriteLine(settings.Span);
}
}
कॉल करने के लिए, एक अजीब सिंटैक्स का उपयोग करें जो सभी को एक ही अभिव्यक्ति में तुरंत और असाइन करने के लिए है:
bar.Foo(); // 00:00:02
bar.Foo(new FooSettings { Span = TimeSpan.FromDays(1), }); // 1.00:00:00
bar.Foo(new FooSettings { Thing = new MyCustomThing(), }); // 00:00:02
downsides
इस समस्या को हल करने के लिए यह वास्तव में हैवीवेट दृष्टिकोण है। यदि आप एक त्वरित और गंदा आंतरिक इंटरफ़ेस लिख रहे हैं और अशक्त बनाने TimeSpan
और अपने वांछित डिफ़ॉल्ट मान की तरह अशक्त बनाने के लिए ठीक काम करेंगे, इसके बजाय ऐसा करें।
इसके अलावा, यदि आपके पास बड़ी संख्या में पैरामीटर हैं या एक तंग लूप में विधि को बुला रहे हैं, तो यह क्लास इंस्टेंटिएशन का ओवरहेड होगा। बेशक, अगर तंग पाश में इस तरह की विधि को कॉल करना, यह स्वाभाविक हो सकता है और यहां तक कि FooSettings
ऑब्जेक्ट के एक उदाहरण का पुन: उपयोग करना बहुत आसान है ।
लाभ
जैसा कि मैंने उदाहरण में टिप्पणी में उल्लेख किया है, मुझे लगता है कि यह पैटर्न सार्वजनिक एपीआई के लिए बहुत अच्छा है। एक वर्ग में नई संपत्तियों को जोड़ना एक गैर-ब्रेकिंग एबीआई परिवर्तन है, इसलिए आप इस पद्धति का उपयोग करके अपनी पद्धति के हस्ताक्षर को बदलने के बिना नए वैकल्पिक पैरामीटर जोड़ सकते हैं - पुराने संकलित कोड का समर्थन करते हुए अधिक हाल ही में संकलित कोड अधिक विकल्प देना, बिना किसी अतिरिक्त काम के। ।
साथ ही, क्योंकि डिफ़ॉल्ट विधि पैरामीटर में निर्मित C # को कंपाइलटाइम स्थिरांक के रूप में माना जाता है और इसे कॉलसाइट में बेक किया जाता है, डिफ़ॉल्ट पैरामीटर केवल कोड द्वारा उपयोग किया जाएगा जब इसे पुन: कनेक्ट किया जाता है। किसी सेटिंग ऑब्जेक्ट को तत्काल करने से, कॉलर आपके सिस्टम को कॉल करते समय डिफ़ॉल्ट मानों को गतिशील रूप से लोड करता है। इसका मतलब है कि आप अपनी सेटिंग कक्षा को बदलकर डिफ़ॉल्ट को अपडेट कर सकते हैं। इस प्रकार, यह पैटर्न नए मानों को देखने के लिए कॉल करने वालों को फिर से इकट्ठा किए बिना डिफ़ॉल्ट मान बदलने देता है, यदि यह वांछित है।
new TimeSpan(2000)
2000 मिलीसेकंड का मतलब यह नहीं है, इसका मतलब 2000 "टिक" है जो 0.2 मिलीसेकंड है, या 10,000 सेकंड का दो सेकंड है।