2012-05-23 15 views
6

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

public void DoSomething(Class1 optional1, Class2 optional2, Class3 optional3) 
    { 
     if (! WasSpecified(optional1)) { optional1 = defaultForOptional1; } 
     if (! WasSpecified(optional2)) { optional2 = defaultForOptional2; } 
     if (! WasSpecified(optional3)) { optional3 = defaultForOptional3; } 

     // ... do the actual work ... 
    } 

मैं Class1 optional1 = null उपयोग नहीं कर सकते क्योंकि अशक्त सार्थक है।

  1. हर संभव संयोजन है, जिसके लिए 8 भार के का मतलब है के साथ भार के प्रदान करें: मैं क्योंकि इन वैकल्पिक पैरामीटर मैं इन विकल्पों के साथ आए हैं के लिए संकलन समय निरंतर आवश्यकता के कुछ प्लेसहोल्डर वर्ग उदाहरण Class1 optional1 = defaultForOptional1 उपयोग नहीं कर सकते यह विधि।
  2. प्रत्येक वैकल्पिक पैरामीटर के लिए एक बूलियन पैरामीटर शामिल करें जो दर्शाता है कि डिफ़ॉल्ट का उपयोग करना है या नहीं, जिसे मैं हस्ताक्षर को अपनाना चाहता हूं।

क्या कोई इस के लिए कुछ चालाक समाधान के साथ आया है?

धन्यवाद!

संपादित करें: मैंने एक रैपर वर्ग लिखना समाप्त कर दिया, इसलिए मुझे Boolean HasFoo दोहराना नहीं पड़ा।

/// <summary> 
    /// A wrapper for variables indicating whether or not the variable has 
    /// been set. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    public struct Setable<T> 
    { 
     // According to http://msdn.microsoft.com/en-us/library/aa288208%28v=vs.71%29.aspx, 
     // "[s]tructs cannot contain explicit parameterless constructors" and "[s]truct 
     // members are automatically initialized to their default values." That's fine, 
     // since Boolean defaults to false and usually T will be nullable. 

     /// <summary> 
     /// Whether or not the variable was set. 
     /// </summary> 
     public Boolean IsSet { get; private set; } 

     /// <summary> 
     /// The variable value. 
     /// </summary> 
     public T Value { get; private set; } 

     /// <summary> 
     /// Converts from Setable to T. 
     /// </summary> 
     /// <param name="p_setable"></param> 
     /// <returns></returns> 
     public static implicit operator T(Setable<T> p_setable) 
     { 
      return p_setable.Value; 
     } 

     /// <summary> 
     /// Converts from T to Setable. 
     /// </summary> 
     /// <param name="p_tee"></param> 
     /// <returns></returns> 
     public static implicit operator Setable<T>(T p_tee) 
     { 
      return new Setable<T> 
      { 
       IsSet = true 
       , Value = p_tee 
      }; 
     } 
    } 
+1

अधिभार आपको शाब्दिक शून्य निरंतर पारित करने नहीं देगा। (बस एक शैली मुद्दा।) – Neil

+0

आप यहां पूरा करने का प्रयास कर रहे हैं? –

उत्तर

10

मैं कम से कम पैरामीटर के लिए एक नए प्रकार बनाने पर विचार करेंगे:

public void DoSomething(DoSomethingOptions options) 

... जहां DoSomethingOptions ऐसा दिखाई दे सकता:

public class DoSomethingOptions 
{ 
    private Class1 class1; 
    public bool HasClass1 { get; private set; } 

    public Class1 Class1 
    { 
     get { return class1; } 
     set 
     { 
      class1 = value; 
      HasClass1 = true; 
     } 
    } 

    ... for other properties ... 
} 

फिर आप इसे कॉल कर सकते हैं:

DoSomething(new DoSomethingOptions { Class1 = null, Class2 = new Class2() }); 

आप अधिभार के घातीय सेट के साथ समाप्त नहीं होते हैं, और आप इसे अभी भी उचित रूप से कॉम्पैक्ट कर सकते हैं।

यह दृष्टिकोण के समान है कि ProcessProcessStartInfo के साथ आता है।

+0

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

7

हर संभव संयोजन है, जो इस विधि के लिए 8 भार के का मतलब है के साथ भार के प्रदान करें।

यह मेरी प्राथमिकता है। यह स्थिति को बहुत स्पष्ट और रखरखाव बनाता है। आंतरिक रूप से, आप डुप्लिकेट कोड को कम करने के लिए एक प्रारंभिक दिनचर्या पर मानचित्र कर सकते हैं।

+1

इस परिदृश्य में (8 ओवरलोड) इसे कुछ हद तक बनाए रखने योग्य माना जा सकता है। लेकिन, यह स्पष्ट रूप से ** ** ** बनाए रखने योग्य नहीं होगा क्योंकि अधिक पैरामीटर आवश्यक हैं। बस कल्पना करें कि उसके पास 5 पैरामीटर थे ... यह 32 भिन्नता है! हां, यह अपने तरीके से अधिक स्पष्ट है, लेकिन रखरखाव एक बड़ी हिट लेता है। फिर फिर, सीए 1026 http://msdn.microsoft.com/en-us/library/ms182135.aspx सार्वजनिक पहुंच के लिए वैकल्पिक पैरामीटर का उपयोग नहीं करता है ... यह सिर्फ पागलपन है। –

+0

@ एम-वाई वास्तव में, यह दुर्लभ है कि प्रत्येक पैरामीटर वैकल्पिक है या वैकल्पिक होना चाहिए, हालांकि - यह केवल सार्थक है। यदि प्रत्येक पैरामीटर वैकल्पिक है, तो मैं एक और अधिक सार्थक डेटा संरचना में प्रतिक्रिया करता हूं। –

+0

@ रीडकोप्सी, जो जॉन स्कीट के उत्तर के साथ संगत है। मैं अधिकतर ट्रांसफर ऑब्जेक्ट का उपयोग करूँगा क्योंकि आप और जॉन सुझाव देते हैं, क्योंकि मेरे पास तीन से अधिक वैकल्पिक पैरामीटर हो सकते हैं। एम-वाई सही है कि बदलाव अत्यधिक हो जाएगा। –

1

हाँ, किसी ऑब्जेक्ट का उपयोग करने का प्रयास करें। एक वर्ग को परिभाषित करें जो संभावित विकल्पों को समाहित करता है। जब ऑब्जेक्ट में कोई विकल्प सेट किया जाता है तो आप उसी ऑब्जेक्ट में स्टोर कर सकते हैं यदि यह मूल प्रॉपर्टी के सेटटर के उपयोग के माध्यम से सेट किया गया हो।

एक उदाहरण:

internal class SettingsHolder 
{ 
    public SettingsHolder() 
    { 
     IsOriginalPropADefault = true; 
    } 

    private Class1 originalProp; 
    public Class1 OriginalProp 
    { 
     get 
     { 
      return originalProp; 
     } 
     set 
     { 
      originalProp = value; 
      IsOriginalPropADefault = false; 
     } 
    } 

    public bool IsOriginalPropADefault { get; private set; } 

} 
6

मैं null मतलब है "कुछ भी नहीं है," और बनाने पसंद करते हैं Class1 पर प्रकार Class1, Class2, आदि की एक static readonly सदस्य है, Class2 आदि None नाम दिया है।फिर null सार्थक बनाने के बजाय आप मूल रूप से इरादे से "कुछ नहीं" के रूप में शून्य का उपयोग कर सकते हैं।

मामले कि भ्रामक है में:

public class Class1 
{ 
    public static readonly Class1 None = new Class1(); 
} 
public static Class2 
{ 
    public static readonly Class2 None = new Class2(); 
} 

ध्यान दें, कि यदि आपके मामले में null "कोई नहीं" के अलावा कुछ का मतलब है ("MissingData" या कुछ और की तरह) आप सदस्य thusly नाम रखना चाहिए। यह भी ध्यान दें: इससे भविष्य में आपके कोड को पढ़ने और उपयोग करने के लिए अन्य लोगों को बहुत अधिक समझदारी होगी।

+0

संबंधित जानकारी के लिए नल ऑब्जेक्ट पैटर्न भी देखें: http://en.wikipedia.org/wiki/Null_Object_pattern (और +1) – BrokenGlass

+0

+1 - हाँ, मैं पूरी तरह से सहमत हूं। ** सत्य ** शून्य के अर्थ को दूर करने के बजाय, एक स्थिर क्षेत्र है जो "कुछ भी नहीं" मान का प्रतिनिधित्व करता है। यह 'स्ट्रिंग। लक्षण' बनाम शून्य की तरह है। –

+0

जैसा कि मैंने कहा, मैं 'शून्य' का उपयोग करके _avoid_ को "कुछ भी नहीं" या "निर्दिष्ट नहीं" करने का प्रयास कर रहा हूं। इस मामले में, 'शून्य' सार्थक है। आपके उदाहरण में, मैं क्लास 1 का उपयोग कैसे करूं। डिफ़ॉल्ट पैरामीटर के रूप में "वैकल्पिक 1 'के लिए डिफ़ॉल्ट पैरामीटर मान" संकलन-समय निरंतर होना चाहिए "? 'सार्वजनिक शून्य DoSomething (कक्षा 1 वैकल्पिक 1 = कक्षा 1.None)' मुझे वह त्रुटि मिलती है। आपके उत्तरों के लिए सभी का धन्यवाद। –

2

आप Flags गणना बना सकते हैं कि आप किन वर्गों का उपयोग करने के लिए यह पारित कर सकते हैं।

[Flags] 
public enum DoSomethingOptions 
{ 
    None = 0, 
    UseClass1 = 1, 
    UseClass2 = 2, 
    UseClass3 = 4, 
    etc.. 
} 

DoSomething(Class1 class1, ..., DoSomethingOptions options = DoSomethingOptions.None) { ... } 

फिर कक्षाओं का उपयोग करने के लिए यह गणना करने के लिए उस गणना को पास करें। मुझे आश्चर्य है कि आपने null का उपयोग शून्य के अलावा कुछ और करने के लिए क्यों किया? हालांकि यह एक समाधान हो सकता है, मैं वास्तव में "अपने डिजाइन पर पुनर्विचार" कहना चाहूंगा।

+0

+1 चालाक विचार। – Crisfole

+0

यह एक अच्छा विचार है। धन्यवाद! –

संबंधित मुद्दे