2012-05-31 25 views
88

this पढ़ना, मुझे पता चला यह संभव था एक विधि यह एक सामान्य विधि बनाकर कई प्रकार के पैरामीटर स्वीकार करने की अनुमति। उदाहरण में, "यू" IEnumerable<T> सुनिश्चित करने के लिए निम्न कोड का उपयोग एक प्रकार की बाधा के साथ किया जाता है।जेनेरिक विधि एकाधिक (या) प्रकार बाधा

public void test<T>(string a, T arg) where T: ParentClass, ChildClass 
{ 
    //do something 
} 

हालांकि, इस कोड को लागू करने की है कि arg दोनों ParentClassऔरChildClass का एक प्रकार होना चाहिए प्रकट होता है:

public T DoSomething<U, T>(U arg) where U : IEnumerable<T> 
{ 
    return arg.First(); 
} 

मैं कुछ और अधिक कोड है जो इस तरह के रूप में कई प्रकार की कमी बताया अनुमति पाया।

public void test<T>(string a, T arg) where T: string OR Exception 
{ 
//do something 
} 

आपका मदद हमेशा के रूप में सराहना की है: मुझे क्या करना चाहते हैं का कहना है कि आर्ग ParentClassया निम्नलिखित तरीके से ChildClass का एक प्रकार हो सकता है!

+3

इस तरह की विधि के शरीर के भीतर * सामान्य रूप से * क्या उपयोगी हो सकता है (जब तक कि कई प्रकार के सभी विशिष्ट वर्ग वर्ग से प्राप्त नहीं होते हैं, इस मामले में क्यों टाइप प्रकार की बाधा के रूप में घोषित नहीं किया जाता है)? –

+0

@Damien_The_Unbeliever यह सुनिश्चित नहीं है कि शरीर में आपका क्या मतलब है? जब तक आप किसी भी प्रकार की अनुमति नहीं दे रहे हैं और मैन्युअल रूप से शरीर में जांच कर रहे हैं ... और वास्तविक कोड में मैं लिखना चाहता हूं (अंतिम कोड स्निपेट), मैं एक स्ट्रिंग या अपवाद पास करने में सक्षम होना चाहता हूं, इसलिए कोई कक्षा नहीं है वहाँ रिश्ते (system.object को छोड़कर मैं कल्पना करता हूं)। – Mansfield

+1

यह भी ध्यान दें कि 'जहां टी: स्ट्रिंग' लिखने में कोई उपयोग नहीं है, क्योंकि 'स्ट्रिंग' ** ** सील ** श्रेणी है। एकमात्र उपयोगी चीज जो आप कर सकते हैं वह 'स्ट्रिंग' और 'टी: अपवाद' के लिए ओवरलोड को परिभाषित कर रही है, जैसा कि नीचे दिए गए उनके उत्तर में @ बॉटज़ 3000 द्वारा समझाया गया है। –

उत्तर

44

संभव नहीं है यही कारण है कि। हालांकि, आप विशिष्ट प्रकार के भार के परिभाषित कर सकते हैं:

public void test(string a, string arg); 
public void test(string a, Exception arg); 

उन एक सामान्य वर्ग का हिस्सा हैं, वे विधि के जेनेरिक संस्करण पर प्राथमिकता दी जाएगी।

+1

दिलचस्प। यह मेरे लिए हुआ था, लेकिन मैंने सोचा कि यह एक समारोह का उपयोग करने के लिए कोड क्लीनर बना सकता है। आह ठीक है, बहुत बहुत धन्यवाद! जिज्ञासा से बाहर, क्या आप जानते हैं कि कोई विशिष्ट कारण यह संभव नहीं है? (क्या यह जानबूझकर भाषा से बाहर छोड़ा गया है?) – Mansfield

+2

@ मैनस्फील्ड मुझे सटीक कारण नहीं पता है, लेकिन मुझे लगता है कि आप जेनेरिक पैरामीटर का अर्थपूर्ण तरीके से उपयोग नहीं कर पाएंगे। कक्षा के अंदर, उन्हें ऑब्जेक्ट की तरह व्यवहार करना होगा यदि उन्हें पूरी तरह से अलग प्रकार के होने की अनुमति थी। इसका मतलब है कि आप सामान्य पैरामीटर को छोड़कर ओवरलोड लोड कर सकते हैं। – Botz3000

+2

@ मैनस्फील्ड, ऐसा इसलिए है क्योंकि एक 'या' रिश्ते चीजों को सामान्य होने के लिए सामान्य बनाता है। आपको यह पता लगाने के लिए प्रतिबिंबित करना होगा कि क्या करना है और यह सब क्या है। (छी!)। – Crisfole

5

ChildClass मतलब है कि यह ParentClass से प्राप्त होता है, तो आप बस दोनों ParentClass और ChildClass स्वीकार करने के लिए निम्नलिखित लिख सकते हैं;

public void test<T>(string a, T arg) where T: ParentClass 
{ 
    //do something 
} 

Otherhand पर, आप उन दोनों के बीच कोई विरासत संबंध के साथ दो अलग अलग प्रकार का उपयोग करना चाहते हैं, तो आप प्रकार एक ही इंटरफ़ेस को लागू करने पर विचार करना चाहिए;

public interface ICommonInterface 
{ 
    string SomeCommonProperty { get; set; } 
} 

public class AA : ICommonInterface 
{ 
    public string SomeCommonProperty 
    { 
     get;set; 
    } 
} 

public class BB : ICommonInterface 
{ 
    public string SomeCommonProperty 
    { 
     get; 
     set; 
    } 
} 

तो आप अपना सामान्य कार्य लिख सकते हैं;

public void Test<T>(string a, T arg) where T : ICommonInterface 
{ 
    //do something 
} 
+0

अच्छा विचार, सिवाय मुझे नहीं लगता कि मैं ऐसा करने में सक्षम हूं क्योंकि मैं स्ट्रिंग का उपयोग करना चाहता हूं जो उपरोक्त टिप्पणी के अनुसार एक सीलबंद वर्ग है ... – Mansfield

+0

यह वास्तव में एक डिजाइन समस्या है। एक सामान्य कार्य कोड पुन: उपयोग के साथ समान संचालन करने के लिए प्रयोग किया जाता है। दोनों यदि आप विधि निकाय में अलग-अलग परिचालन करने की योजना बना रहे हैं, तो पृथक तरीके एक बेहतर तरीका है (आईएमएचओ)। – daryal

+0

मैं जो कर रहा हूं, वास्तव में, एक साधारण त्रुटि लॉगिंग फ़ंक्शन लिख रहा है। मैं उस अंतिम पैरामीटर को या तो त्रुटि, या अपवाद के बारे में जानकारी की एक स्ट्रिंग होना चाहता हूं, जिस स्थिति में मैं e.message + e.stacktrace को स्ट्रिंग के रूप में सहेजता हूं। – Mansfield

18

Botz जवाब 100% सही है, यहाँ एक संक्षिप्त विवरण है:

आप एक विधि (सामान्य या नहीं) लेखन और पैरामीटर विधि आप एक अनुबंध को परिभाषित कर रहे लेता है के प्रकार की घोषणा कर रहे हैं :

तुम मुझे एक वस्तु को पता है कि चीजों में से सेट प्रकार टी जानता है कि कैसे मैं या तो 'एक' वितरित कर सकते हैं करने के लिए कैसे करना देते हैं: मैं घोषणा प्रकार का एक वापसी मान, या ' बी ': उस प्रकार का व्यवहार जो उस प्रकार का उपयोग करता है।

आप कोशिश करते हैं और यह (एक या होने से) एक समय में एक से अधिक प्रकार दे सकते हैं या यह एक मूल्य है कि एक से अधिक प्रकार है कि अनुबंध फजी हो जाता है हो सकता है वापस जाने के लिए प्राप्त करने की कोशिश करते हैं:

तुम मुझे एक वस्तु कैसे रस्सी कूदने के लिए जानता है या कैसे 15 वीं अंकों मैं या तो एक उद्देश्य यह है कि मछली पकड़ने जा सकते हैं या हो सकता है ठोस मिश्रण आरंभ कर देंगे करने के लिए अनुकरणीय गणना करने के लिए जानता है कि देते हैं।

समस्या आप कोई अंदाज़ा नहीं है कि जब आप विधि में मिल अगर वे आप एक IJumpRope या एक PiFactory दिया है है। इसके अलावा, जब आप आगे बढ़ते हैं और विधि का उपयोग करते हैं (यह मानते हुए कि आप इसे जादुई रूप से संकलित करने के लिए प्राप्त कर चुके हैं) तो आप वास्तव में सुनिश्चित नहीं हैं कि आपके पास Fisher या AbstractConcreteMixer है। असल में यह पूरी चीज को और अधिक भ्रमित कर देता है।

आपकी समस्या का हल दो possiblities में से एक है:

  1. एक से अधिक विधि है कि प्रत्येक संभव परिवर्तन, व्यवहार, या जो कुछ भी परिभाषित करता है परिभाषित करें। वह बोटज़ का जवाब है। प्रोग्रामिंग दुनिया में इसे विधि को अधिभारित करने के रूप में जाना जाता है।

  2. एक बेस क्लास या इंटरफ़ेस को परिभाषित करें जो जानता है कि विधि के लिए आपको आवश्यक सभी चीजें कैसे करें और एक विधि केवल टाइप करें। इसमें एक छोटे से वर्ग में string और Exception को लपेटना शामिल हो सकता है ताकि यह परिभाषित किया जा सके कि आप उन्हें कार्यान्वयन के लिए मानचित्रण करने की योजना कैसे बनाते हैं, लेकिन फिर सब कुछ स्पष्ट और पढ़ने में आसान है। मैं अब से चार साल आ सकता हूं और अपना कोड पढ़ सकता हूं और आसानी से समझ सकता हूं कि क्या हो रहा है।

जो आप चुनते हैं उस पर निर्भर करता है कि जटिल विकल्प 1 और 2 कितना होगा और यह कितना एक्स्टेंसिबल होना चाहिए।

तो अपने विशिष्ट स्थिति के लिए मैं तुम्हें सिर्फ एक संदेश या अपवाद से कुछ बाहर खींच रहे कल्पना करने के लिए जा रहा हूँ:

public interface IHasMessage 
{ 
    string GetMessage(); 
} 

public void test(string a, IHasMessage arg) 
{ 
    //Use message 
} 

अब तुम सब तरीकों कि एक string परिणत कर रहे हैं की जरूरत है और एक Exception को एक IHasMessage। बहुत आसान।

+0

क्षमा करें @ Botz3000, मैंने देखा है कि मैंने आपका नाम गलत लिखा है। – Crisfole

+0

या कंपाइलर फ़ंक्शन के भीतर एक यूनियन प्रकार के रूप में प्रकार को खतरे में डाल सकता है और वापसी मूल्य उसी प्रकार का हो सकता है जिसमें यह हो जाता है। टाइपस्क्रिप्ट यह करता है। – Alex

+0

@ एलेक्स लेकिन यह नहीं है कि सी # क्या करता है। – Crisfole

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