क्या आपको C # 4.0 में ओवरलोड या वैकल्पिक मापदंडों का उपयोग करते हुए विधियों की घोषणा करनी चाहिए?


93

मैं सी # 4.0 के बारे में एंडर्स की बात देख रहा था और सी # 5.0 के चुपके पूर्वावलोकन , और यह मेरे बारे में सोच रहा था कि जब वैकल्पिक पैरामीटर सी # में उपलब्ध हैं, तो उन तरीकों को घोषित करने के लिए अनुशंसित तरीका क्या होगा जो निर्दिष्ट सभी मापदंडों की आवश्यकता नहीं है?

उदाहरण के लिए कुछ ऐसा होता है जैसे FileStreamकक्षा में लगभग पंद्रह अलग-अलग निर्माता होते हैं जिन्हें तार्किक 'परिवारों' में विभाजित किया जा सकता IntPtrहै SafeFileHandle

FileStream(string,FileMode);
FileStream(string,FileMode,FileAccess);
FileStream(string,FileMode,FileAccess,FileShare);
FileStream(string,FileMode,FileAccess,FileShare,int);
FileStream(string,FileMode,FileAccess,FileShare,int,bool);

मुझे ऐसा लगता है कि इस प्रकार के पैटर्न को तीन बिल्डरों के बजाय सरल बनाया जा सकता है, और जो डिफ़ॉल्ट हो सकते हैं उनके लिए वैकल्पिक मापदंडों का उपयोग करके, जो कि बिल्डरों के विभिन्न परिवारों को और अधिक विशिष्ट बना देगा [नोट: मुझे पता है कि यह परिवर्तन नहीं होगा बीसीएल में बने, मैं इस प्रकार की स्थिति के लिए काल्पनिक रूप से बात कर रहा हूं]।

तुम क्या सोचते हो? सी # 4.0 से, यह कंस्ट्रक्टरों के निकट संबंधित समूहों और विधियों को वैकल्पिक मापदंडों के साथ एक एकल विधि बनाने के लिए अधिक समझ में आएगा, या पारंपरिक कई-अधिभार तंत्र के साथ छड़ी करने का एक अच्छा कारण है?

जवाबों:


121

मैं निम्नलिखित पर विचार करूंगा:

  • क्या आपको अपने कोड का उपयोग उन भाषाओं से करने की आवश्यकता है जो वैकल्पिक मापदंडों का समर्थन नहीं करते हैं? यदि हां, तो ओवरलोड सहित विचार करें।
  • क्या आपकी टीम में कोई सदस्य है जो वैकल्पिक मापदंडों का उल्लंघन करता है? (कभी-कभी ऐसे निर्णय के साथ रहना आसान होता है, जिसे आप बहस के लिए पसंद नहीं करते।)
  • क्या आप आश्वस्त हैं कि आपकी चूक आपके कोड के निर्माण के बीच नहीं बदलेगी, या यदि वे हो सकते हैं, तो क्या आपके कॉल करने वाले ठीक होंगे?

मैंने जाँच नहीं की है कि डिफॉल्ट कैसे काम कर रहे हैं, लेकिन मैं मान लूंगा कि डिफ़ॉल्ट मान कॉलिंग कोड में बेक किए जाएंगे, जो कि constफ़ील्ड के संदर्भ में बहुत समान हैं। यह आमतौर पर ठीक है - डिफ़ॉल्ट मान में परिवर्तन वैसे भी बहुत महत्वपूर्ण हैं - लेकिन उन बातों पर विचार करना चाहिए।


21
व्यावहारिकता पर ज्ञान के लिए +1: कभी-कभी ऐसे निर्णय के साथ रहना आसान होता है जिसे आप इस मामले में बहस करना पसंद नहीं करते।
लीजेंड 2k

13
@romkyns: नहीं, ओवरलोड का प्रभाव बिंदु 3 के साथ समान नहीं है। ओवरलोड के साथ डिफॉल्ट प्रदान करने के साथ, डिफॉल्ट लाइब्रेरी कोड के भीतर हैं - इसलिए यदि आप डिफ़ॉल्ट को बदलते हैं और लाइब्रेरी का एक नया संस्करण प्रदान करते हैं, तो कॉलर्स करेंगे पुनर्संयोजन के बिना नया डिफ़ॉल्ट देखें। जबकि वैकल्पिक मापदंडों के साथ, आपको नए डिफॉल्ट्स को "देखने" के लिए फिर से तैयार करना होगा। समय का एक बहुत यह एक महत्वपूर्ण अंतर नहीं है, लेकिन यह है एक अंतर।
जॉन स्कीट

हाय @JonSkeet, मैं जानना चाहूंगा कि क्या हम वैकल्पिक पैरामैटर के साथ दोनों का उपयोग करते हैं और अन्य ओवरलोडिंग के साथ किस विधि को कहा जाएगा ?? जैसे Add (int a, int b) और Add (int a, int b, int c = 0) और function call का कहना है: Add (5,00); किस विधि को अतिभारित फ़ंक्शन या वैकल्पिक पैरामीटर फ़ंक्शन कहा जाएगा? धन्यवाद :)
SHEKHAR SHETE

@ शेखर: क्या आपने इसकी कोशिश की है? विवरण के लिए कल्पना पढ़ें, लेकिन मूल रूप से टाई-ब्रेकर में एक विधि जहां संकलक को किसी भी वैकल्पिक पैरामीटर जीत में नहीं भरना पड़ता है।
जॉन स्कीट

@JonSkeet अभी मैंने ऊपर से कोशिश की ... फंक्शन ओवरलोडिंग वैकल्पिक पैरामीटर पर जीतता है :)
SHEKHAR SHETE

19

जब एक विधि अधिभार सामान्य रूप से एक अलग संख्या के तर्कों के साथ एक ही कार्य करता है तो चूक का उपयोग किया जाएगा।

जब एक विधि अधिभार अपने मापदंडों के आधार पर एक कार्य को अलग ढंग से करता है तो ओवरलोडिंग का उपयोग करना जारी रहेगा।

मैंने अपने VB6 दिनों में वैकल्पिक रूप से वापस उपयोग किया और जब से यह छूट गया है, यह C # में XML टिप्पणी दोहराव को बहुत कम कर देगा।


11

मैं हमेशा के लिए वैकल्पिक मापदंडों के साथ डेल्फी का उपयोग कर रहा हूं। मैंने इसके बजाय ओवरलोड का उपयोग करने के लिए स्विच किया है।

क्योंकि जब आप अधिक अधिभार बनाने के लिए जाते हैं, तो आप वैकल्पिक रूप से एक वैकल्पिक पैरामीटर फॉर्म के साथ संघर्ष करेंगे, और फिर आपको उन्हें किसी भी तरह गैर-वैकल्पिक में बदलना होगा।

और मुझे यह धारणा पसंद है कि आम तौर पर एक है सुपर विधि है, और बाकी उस एक के आसपास सरल आवरण हैं।


1
मैं इससे बहुत सहमत हूं, हालांकि यह चेतावनी है कि जब आपके पास एक विधि है जो कई (3+) मापदंडों को लेती है, जो कि प्रकृति द्वारा सभी "वैकल्पिक" हैं (डिफ़ॉल्ट रूप से प्रतिस्थापित किया जा सकता है) तो आप कई क्रमपरिवर्तन के साथ समाप्त हो सकते हैं कोई और अधिक लाभ के लिए विधि हस्ताक्षर की। पर विचार करें Foo(A, B, C)की आवश्यकता है Foo(A), Foo(B), Foo(C), Foo(A, B), Foo(A, C), Foo(B, C)
डेन लैग

7

मैं निश्चित रूप से 4.0 के वैकल्पिक मापदंडों की सुविधा का उपयोग कर रहा हूं। इससे छुटकारा मिलता है ...

public void M1( string foo, string bar )
{
   // do that thang
}

public void M1( string foo )
{
  M1( foo, "bar default" ); // I have always hated this line of code specifically
}

... और मान डालता है जहाँ कॉलर उन्हें देख सकता है ...

public void M1( string foo, string bar = "bar default" )
{
   // do that thang
}

बहुत अधिक सरल और बहुत कम त्रुटि प्रवण। मैं वास्तव में यह अधिभार मामले में एक बग के रूप में देखा है ...

public void M1( string foo )
{
   M2( foo, "bar default" );  // oops!  I meant M1!
}

मैंने अभी तक 4.0 के साथ नहीं खेला है, लेकिन मुझे यह जानकर कोई आघात नहीं होगा कि कॉम्प्लीमेंट केवल आपके लिए ओवरलोड का उत्सर्जन करता है।


6

वैकल्पिक पैरामीटर अनिवार्य रूप से मेटाडेटा का एक टुकड़ा है जो एक संकलक को निर्देश देता है जो कॉल साइट पर उपयुक्त चूक सम्मिलित करने के लिए एक विधि कॉल को संसाधित कर रहा है। इसके विपरीत, ओवरलोड एक ऐसा साधन प्रदान करते हैं जिसके द्वारा एक संकलक कई विधियों में से एक का चयन कर सकता है, जिनमें से कुछ स्वयं डिफ़ॉल्ट मानों की आपूर्ति कर सकते हैं। ध्यान दें कि यदि कोई ऐसी विधि को कॉल करने की कोशिश करता है जो किसी भाषा में लिखे गए कोड से वैकल्पिक मापदंडों को निर्दिष्ट करता है जो उनका समर्थन नहीं करता है, तो संकलक को "वैकल्पिक" मापदंडों को निर्दिष्ट करने की आवश्यकता होगी, लेकिन चूंकि वैकल्पिक पैरामीटर को निर्दिष्ट किए बिना एक विधि को कॉल करना है। डिफ़ॉल्ट मान के बराबर पैरामीटर के साथ इसे कॉल करने के बराबर है, ऐसी भाषाओं में ऐसी विधियों को कॉल करने में कोई बाधा नहीं है।

कॉल साइट पर वैकल्पिक मापदंडों के बंधन का एक महत्वपूर्ण परिणाम यह है कि उन्हें लक्ष्य कोड के संस्करण के आधार पर मान निर्दिष्ट किया जाएगा जो संकलक के लिए उपलब्ध है। यदि असेंबली Fooमें Boo(int)5 के डिफ़ॉल्ट मान के साथ एक विधि होती है, और असेंबली Barमें कॉल होता है Foo.Boo(), तो कंपाइलर प्रक्रिया करेगा कि a Foo.Boo(5)। यदि डिफ़ॉल्ट मान को 6 में बदल दिया जाता है और असेंबली Fooको पुन: कनेक्ट किया जाता है, तब तक Barकॉल करना जारी रहेगा Foo.Boo(5)जब तक कि उस नए संस्करण के साथ पुन: कनेक्ट नहीं किया जाता Foo। इस प्रकार उन चीजों के लिए वैकल्पिक मापदंडों का उपयोग करने से बचना चाहिए जो बदल सकते हैं।


पुन: "इस प्रकार चीजों को बदलने के लिए वैकल्पिक मापदंडों के उपयोग से बचना चाहिए।" मैं इस बात से सहमत हूं कि यदि ग्राहक कोड द्वारा परिवर्तन पर किसी का ध्यान नहीं जाता है तो यह समस्याग्रस्त हो सकता है। हालाँकि, एक ही समस्या मौजूद है जब डिफ़ॉल्ट मान एक विधि अधिभार के अंदर छिपा हुआ है void Foo(int value) … void Foo() { Foo(42); }:। बाहर से, कॉल करने वाले को यह नहीं पता होता है कि क्या डिफ़ॉल्ट मूल्य का उपयोग किया जाता है, न ही जब यह बदल सकता है; उसके लिए लिखित दस्तावेज की निगरानी करनी होगी। वैकल्पिक मापदंडों के लिए डिफ़ॉल्ट मानों को बस इस रूप में देखा जा सकता है: प्रलेखन-इन-कोड डिफ़ॉल्ट मान क्या है।
stakx - अब

@stakx: यदि एक पैरामीटर के साथ एक अधिभार के लिए एक पैरामीटर रहित अधिभार चेन, उस पैरामीटर के "डिफ़ॉल्ट" मान को बदल रहा है और अधिभार की परिभाषा को फिर से लोड कर रहा है, तो कॉल कोड पुन: संकलित होने पर भी इसका उपयोग करने वाले मूल्य को बदल देगा ।
सुपरकैट

यह सच है लेकिन यह विकल्प की तुलना में अधिक समस्याग्रस्त नहीं है। एक मामले में (विधि अधिभार), कॉलिंग कोड का डिफ़ॉल्ट मान में कोई कहना नहीं है। यह उपयुक्त हो सकता है यदि कॉलिंग कोड वास्तव में वैकल्पिक पैरामीटर के बारे में बिल्कुल भी परवाह नहीं करता है और इसका क्या मतलब है। दूसरे मामले में (डिफ़ॉल्ट मान के साथ वैकल्पिक पैरामीटर), डिफ़ॉल्ट मान में परिवर्तन होने पर पहले संकलित कॉलिंग कोड प्रभावित नहीं होगा। यह तब भी उचित हो सकता है जब कॉलिंग कोड वास्तव में पैरामीटर की परवाह करता है; इसे स्रोत में छोड़ना यह कहने जैसा है, "वर्तमान में सुझाया गया डिफ़ॉल्ट मान मेरे लिए ठीक है।"
स्टाक्स -

जिस बिंदु पर मैं यहां बात करने की कोशिश कर रहा हूं, वह यह है कि जब तक दृष्टिकोण (जैसे आपने बताया) के परिणाम हैं, वे स्वाभाविक रूप से लाभप्रद या नुकसानदेह नहीं हैं। यह कॉलिंग कोड की जरूरतों और लक्ष्यों पर भी निर्भर करता है। उस POV से, मुझे आपके उत्तर के अंतिम वाक्य में फैसला कुछ हद तक कठोर लगा।
stakx - अब

@stakx: मैंने कहा कि "कभी उपयोग न करें" के बजाय "उपयोग करने से बचें"। यदि X को बदलने का अर्थ होगा कि Y का अगला पुनर्संयोजन Y के व्यवहार को बदल देगा, तो इसके लिए या तो एक निर्माण प्रणाली को कॉन्फ़िगर करने की आवश्यकता होगी ताकि X का प्रत्येक पुनर्संयोजन Y भी recompiles Y (चीजों को धीमा कर दे), या एक प्रोग्रामर बदल जाएगा जोखिम पैदा करें एक तरह से X, जो Y को अगली बार संकलित करने के लिए तोड़ देगा, और केवल बाद में ऐसे टूटने की खोज करेगा जब Y को पूरी तरह से असंबंधित कारण से बदल दिया जाए। डिफ़ॉल्ट मापदंडों का उपयोग केवल तब किया जाना चाहिए जब उनके फायदे ऐसी लागतों को पछाड़ दें।
सुपरकैट

4

यह तर्क दिया जा सकता है कि वैकल्पिक तर्क या अधिभार का उपयोग किया जाना चाहिए या नहीं, लेकिन सबसे महत्वपूर्ण बात यह है कि प्रत्येक का अपना क्षेत्र है जहां वे अपूरणीय हैं।

वैकल्पिक तर्क, जब नामित तर्कों के साथ संयोजन में उपयोग किए जाते हैं, तो COM कॉल के कुछ लंबे-तर्क-सूचियों-सभी-वैकल्पिक के साथ संयुक्त होने पर बेहद उपयोगी होते हैं।

जब कई अलग-अलग तर्क प्रकारों (उदाहरणों में से एक) पर काम करने में सक्षम हो, तो ओवरलोड बेहद उपयोगी होते हैं, और उदाहरण के लिए, आंतरिक रूप से कास्टिंग करते हैं; आप इसे किसी भी डेटा प्रकार के साथ फ़ीड करते हैं जो समझ में आता है (जो कि कुछ मौजूदा अधिभार द्वारा स्वीकार किया जाता है)। वैकल्पिक तर्क के साथ इसे हरा नहीं सकते।


3

मैं वैकल्पिक मापदंडों की प्रतीक्षा कर रहा हूं क्योंकि यह यह बताता है कि क्या चूक विधि के करीब हैं। इसलिए ओवरलोड के लिए दर्जनों लाइनों के बजाय जो "विस्तारित" विधि को कॉल करते हैं, आप बस एक बार विधि को परिभाषित करते हैं और आप देख सकते हैं कि वैकल्पिक हस्ताक्षर विधि के हस्ताक्षर में क्या डिफ़ॉल्ट हैं। मैं इसके बजाय देखूंगा:

public Rectangle (Point start = Point.Zero, int width, int height)
{
    Start = start;
    Width = width;
    Height = height;
}

इसके अलावा:

public Rectangle (Point start, int width, int height)
{
    Start = start;
    Width = width;
    Height = height;
}

public Rectangle (int width, int height) :
    this (Point.Zero, width, height)
{
}

जाहिर है कि यह उदाहरण वास्तव में सरल है, लेकिन ओपी में मामला 5 अधिभार के साथ है, चीजों को वास्तविक रूप से भीड़ मिल सकती है।


7
मैंने सुना है कि वैकल्पिक पैरामीटर अंतिम होना चाहिए, क्या उन्हें नहीं होना चाहिए?
इल्या रायज़ेनकोव

आपके डिजाइन पर निर्भर करता है। शायद 'शुरू' तर्क आम तौर पर महत्वपूर्ण है, सिवाय इसके कि जब यह नहीं है। शायद आपके पास कहीं और एक ही हस्ताक्षर है, जिसका अर्थ कुछ अलग है। एक आकस्मिक उदाहरण के लिए, सार्वजनिक आयत (इंट चौड़ाई, इंट ऊंचाई, प्वाइंट इनरसक्वेयरस्टार्ट, पॉइंट इनरसक्वेयरएंड) {}
रॉबर्ट पी

13
बातों-बातों में उन्होंने जो कहा, उसमें से आवश्यक मापदंडों के बाद वैकल्पिक पैरामीटर होना चाहिए।
ग्रेग बीच 22

3

वैकल्पिक मापदंडों के मेरे पसंदीदा पहलुओं में से एक यह है कि आप देखते हैं कि आपके मापदंडों का क्या होता है यदि आप उन्हें प्रदान नहीं करते हैं, भले ही विधि की परिभाषा पर जाए बिना। जब आप विधि का नाम लिखते हैं तो विज़ुअल स्टूडियो आपको पैरामीटर के लिए डिफ़ॉल्ट मान दिखाएगा । एक अधिभार विधि के साथ आप या तो प्रलेखन (यदि उपलब्ध भी हो) या सीधे विधि की परिभाषा (यदि उपलब्ध हो) पर नेविगेट करने के साथ और अधिभार लपेटने की विधि के साथ फंस गए हैं।

विशेष रूप से: ओवरलोड की मात्रा के साथ प्रलेखन का प्रयास तेजी से बढ़ सकता है, और आप संभवतः मौजूदा अधिभार से पहले से मौजूद टिप्पणियों की नकल करेंगे। यह काफी कष्टप्रद है, क्योंकि यह किसी भी मूल्य का उत्पादन नहीं करता है और DRY- सिद्धांत को तोड़ता है )। दूसरी ओर, एक वैकल्पिक पैरामीटर के साथ बिल्कुल एक जगह होती है, जहां सभी मापदंडों को प्रलेखित किया जाता है और आप उनका अर्थ और साथ ही उनके डिफ़ॉल्ट मान टाइप करते हुए देखते हैं ।

अंतिम लेकिन कम से कम, यदि आप एक एपीआई के उपभोक्ता हैं, तो आपके पास कार्यान्वयन विवरणों (यदि आपके पास स्रोत कोड नहीं है) का निरीक्षण करने का विकल्प भी नहीं हो सकता है और इसलिए यह देखने का कोई मौका नहीं है कि कौन सी सुपर विधि अतिभारित है लपेट रहे हैं। इस प्रकार आप डॉक्टर को पढ़ रहे हैं और उम्मीद कर रहे हैं कि सभी डिफ़ॉल्ट मान वहाँ सूचीबद्ध हैं, लेकिन यह हमेशा ऐसा नहीं होता है।

बेशक, यह एक जवाब नहीं है जो सभी पहलुओं को संभालता है, लेकिन मुझे लगता है कि यह एक जोड़ता है जिसे अब तक कवर नहीं किया गया है।


1

हालांकि, वे आपके एपीआई को खरोंच से मॉडल करने के लिए (वैचारिक रूप से) दो वैचारिक रूप से उपलब्ध हैं, लेकिन दुर्भाग्य से कुछ सूक्ष्म अंतर हैं जब आपको जंगल में अपने पुराने ग्राहकों के लिए रनटाइम बैकवर्ड संगतता पर विचार करने की आवश्यकता होती है। मेरे सहकर्मी (धन्यवाद ब्रेंट!) ने मुझे इस अद्भुत पोस्ट की ओर इशारा किया : वैकल्पिक तर्कों के साथ मुद्दों का संस्करण । इसमें से कुछ बोली:

पहली बार C # 4 में वैकल्पिक पैरामीटर पेश किए जाने का कारण COM इंटरॉप का समर्थन करना था। बस। और अब, हम इस तथ्य के पूर्ण निहितार्थ के बारे में सीख रहे हैं। यदि आपके पास वैकल्पिक मापदंडों के साथ एक विधि है, तो आप संकलन-समय ब्रेकिंग परिवर्तन के डर से अतिरिक्त वैकल्पिक मापदंडों के साथ एक अधिभार नहीं जोड़ सकते हैं। और आप एक मौजूदा अधिभार को कभी नहीं हटा सकते हैं, क्योंकि यह हमेशा एक रनटाइम ब्रेकिंग परिवर्तन रहा है। आपको एक इंटरफ़ेस की तरह इसका इलाज करने की बहुत आवश्यकता है। इस मामले में आपका एकमात्र सहारा एक नए नाम के साथ एक नई विधि लिखना है। यदि आप अपने एपीआई में वैकल्पिक तर्कों का उपयोग करने की योजना बनाते हैं, तो इसके बारे में जानकारी रखें।


1

वैकल्पिक मापदंडों में से एक चेतावनी है, जहां एक रिफ्लेक्टर के अनपेक्षित परिणाम हैं। एक उदाहरण:

प्रारंभिक कोड

public string HandleError(string message, bool silent=true, bool isCritical=true)
{
  ...
}

मान लें कि यह उपरोक्त विधि के कई कॉलर्स में से एक है:

HandleError("Disk is full", false);

यहाँ घटना मौन नहीं है और इसे गंभीर माना जाता है।

अब कहते हैं कि एक रिफ्लेक्टर के बाद हम पाते हैं कि सभी त्रुटियां वैसे भी उपयोगकर्ता को संकेत देती हैं, इसलिए हमें अब मूक ध्वज की आवश्यकता नहीं है। इसलिए हम इसे हटा देते हैं।

रिफ्लेक्टर के बाद

पूर्व कॉल अभी भी संकलित है, और मान लें कि यह रिफ्लेक्टर के माध्यम से अपरिवर्तित है:

public string HandleError(string message, /*bool silent=true,*/ bool isCritical=true)
{
  ...
}

...

// Some other distant code file:
HandleError("Disk is full", false);

अब falseएक अनपेक्षित प्रभाव होगा, इस घटना को अब गंभीर नहीं माना जाएगा।

इसके परिणामस्वरूप एक सूक्ष्म दोष हो सकता है, क्योंकि कोई संकलन या रनटाइम त्रुटि नहीं होगी (वैकल्पिक के कुछ अन्य कैविट्स के विपरीत, जैसे कि यह या यह )।

ध्यान दें कि इसी समस्या के कई रूप हैं। एक दूसरे रूप को यहाँ रेखांकित किया गया है

यह भी ध्यान दें कि विधि को कॉल करते समय नामित मापदंडों का सख्ती से उपयोग करना समस्या से बचाएगा, जैसे HandleError("Disk is full", silent:false):। हालाँकि, यह मानना ​​व्यावहारिक नहीं होगा कि अन्य सभी डेवलपर्स (या सार्वजनिक एपीआई के उपयोगकर्ता) ऐसा करेंगे।

इन कारणों से मैं एक सार्वजनिक एपीआई में वैकल्पिक मापदंडों (या यहां तक ​​कि अगर इसे व्यापक रूप से उपयोग किया जा सकता है) का उपयोग करने से बचना चाहिए जब तक कि अन्य सम्मोहक विचार न हों।


0

दोनों वैकल्पिक पैरामीटर, विधि अधिभार का अपना लाभ या नुकसान है। यह उन दोनों के बीच चयन करने के लिए आपकी प्राथमिकता पर निर्भर करता है।

वैकल्पिक पैरामीटर: केवल .Net 4.0 में उपलब्ध है। वैकल्पिक पैरामीटर आपके कोड का आकार कम करता है। आप पैरामीटर को परिभाषित और परिष्कृत नहीं कर सकते

अतिभारित तरीके: आप मापदंडों को परिभाषित और परिष्कृत कर सकते हैं। कोड का आकार बढ़ेगा लेकिन अधिभार विधि को समझना आसान है।


0

कई मामलों में निष्पादन को स्विच करने के लिए वैकल्पिक मापदंडों का उपयोग किया जाता है। उदाहरण के लिए:

decimal GetPrice(string productName, decimal discountPercentage = 0)
{

    decimal basePrice = CalculateBasePrice(productName);

    if (discountPercentage > 0)
        return basePrice * (1 - discountPercentage / 100);
    else
        return basePrice;
}

यहाँ पर डिस्काउंट पैरामीटर का उपयोग if-then-अन्यथा स्टेटमेंट को फीड करने के लिए किया जाता है। वहाँ बहुरूपता है कि मान्यता प्राप्त नहीं था, और फिर यह एक if-then-अन्यथा कथन के रूप में लागू किया गया था। ऐसे मामलों में, दो नियंत्रण प्रवाह को दो स्वतंत्र तरीकों में विभाजित करना बेहतर होता है:

decimal GetPrice(string productName)
{
    decimal basePrice = CalculateBasePrice(productName);
    return basePrice;
}

decimal GetPrice(string productName, decimal discountPercentage)
{

    if (discountPercentage <= 0)
        throw new ArgumentException();

    decimal basePrice = GetPrice(productName);

    decimal discountedPrice = basePrice * (1 - discountPercentage / 100);

    return discountedPrice;

}

इस तरह, हमने कक्षा को शून्य छूट के साथ कॉल प्राप्त करने से भी सुरक्षित रखा है। उस कॉल का मतलब होगा कि कॉल करने वाले को लगता है कि छूट है, लेकिन वास्तव में कोई छूट नहीं है। इस तरह की गलतफहमी आसानी से बग पैदा कर सकती है।

इस तरह के मामलों में, मैं वैकल्पिक पैरामीटर नहीं रखना पसंद करता हूं, लेकिन कॉल करने वाले को स्पष्ट रूप से निष्पादन परिदृश्य का चयन करने के लिए मजबूर करना है जो इसकी वर्तमान स्थिति के अनुरूप है।

स्थिति बहुत ही ऐसे मापदंडों के समान है जो शून्य हो सकते हैं। यह उतना ही बुरा विचार है जब कार्यान्वयन बयानों की तरह उबलता है if (x == null)

आप इन लिंक्स पर विस्तृत विश्लेषण पा सकते हैं: वैकल्पिक पैरामीटर्स से बचना और अशक्त पैरामीटर से बचना


0

वैकल्पिक के बजाय जब एक अधिभार का उपयोग करने के लिए कोई ब्रेनर जोड़ने के लिए:

जब भी आपके पास कई पैरामीटर हैं जो केवल एक साथ समझ में आते हैं, तो उन पर वैकल्पिक का परिचय न दें।

या अधिक आम तौर पर, जब भी आपके विधि हस्ताक्षर उपयोग पैटर्न को सक्षम करते हैं जो समझ में नहीं आता है, संभव कॉल की क्रमपरिवर्तन की संख्या को सीमित करें। उदाहरण के लिए, वैकल्पिक के बजाय ओवरलोड का उपयोग करके (यह नियम भी सही है जब आपके पास एक ही डेटाटाइप के कई पैरामीटर हैं, वैसे, यहां, कारखाने के तरीकों या कस्टम डेटा प्रकार जैसे डिवाइस मदद कर सकते हैं)।

उदाहरण:

enum Match {
    Regex,
    Wildcard,
    ContainsString,
}

// Don't: This way, Enumerate() can be called in a way
//         which does not make sense:
IEnumerable<string> Enumerate(string searchPattern = null,
                              Match match = Match.Regex,
                              SearchOption searchOption = SearchOption.TopDirectoryOnly);

// Better: Provide only overloads which cannot be mis-used:
IEnumerable<string> Enumerate(SearchOption searchOption = SearchOption.TopDirectoryOnly);
IEnumerable<string> Enumerate(string searchPattern, Match match,
                              SearchOption searchOption = SearchOption.TopDirectoryOnly);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.