2008-09-23 24 views
5

मैं .NET जेनेरिक की अवधारणा को समझने की कोशिश कर रहा हूं और वास्तव में उन्हें अपने कोड में उपयोग करता हूं लेकिन मैं एक समस्या में चल रहा हूं।.NET जेनेरिक विधि प्रश्न

क्या कोई मुझे यह बताने की कोशिश कर सकता है कि निम्न सेटअप संकलित क्यों नहीं करता है?

public class ClassA 
{ 
    ClassB b = new ClassB(); 

    public void MethodA<T>(IRepo<T> repo) where T : ITypeEntity 
    { 
     b.MethodB(repo); 
    } 
} 

public class ClassB 
{ 
    IRepo<ITypeEntity> repo; 

    public void MethodB(IRepo<ITypeEntity> repo) 
    { 
     this.repo = repo; 
    } 
} 

मैं निम्नलिखित त्रुटि मिलती है:
'iRepo < को टी>' iRepo < से परिवर्तित नहीं कर सकते ITypeEntity>

MethodA एक iRepo < 'DetailType> वस्तु पैरामीटर जहां DetailType ITypeEntity से विरासत के साथ बुलाया जाता है ।

मैं सोचता रहता हूं कि यह संकलित होना चाहिए क्योंकि मैं विधि टाइप के भीतर टी को बाध्य कर रहा हूं, टाइप प्रकार ITypeEntity।

कोई भी विचार या प्रतिक्रिया अत्यंत उपयोगी होगी।

धन्यवाद।

संपादित करें: निक आर का एक अच्छा सुझाव है लेकिन दुर्भाग्य से मेरे संदर्भ में, मेरे पास क्लास जेनेरिक बनाने का विकल्प नहीं है। कक्षा बी हालांकि हो सकता है।

उत्तर

3

विरासत जब जेनरिक का उपयोग कर एक ही काम नहीं करता। Smashery बताते हैं, भले ही typeâ TypeB, MyType < typeâ से विरासत>> MyType < TypeB से विरासत नहीं है।

इस तरह के रूप में, आप एक विधि MethodA के रूप में परिभाषित (MyType < TypeB> ख) एक MyType < TypeB उम्मीद करने के लिए एक कॉल नहीं कर सकते> और यह एक MyType < typeâ> बजाय दे। प्रश्नों के प्रकार बिल्कुल मेल खाते हैं। इस प्रकार, निम्नलिखित संकलन नहीं होगा:

myType<TypeA> a; // This should be a myType<TypeB>, even if it contains only TypeA's 

public void MethodB(myType<TypeB> b){ /* do stuff */ } 

public void Main() 
{ 
    MethodB(a); 
} 

तो आपके मामले में, आप एक iRepo < ITypeEntity> MethodB करने के लिए पारित करने के लिए की आवश्यकता होगी, भले ही वह केवल DetailTypes शामिल हैं। आपको दोनों के बीच कुछ रूपांतरण करना होगा। आप एक सामान्य IList उपयोग कर रहे थे, तो आप निम्न कर सकते हैं:

public void MethodA<T>(IList<T> list) where T : ITypeEntity 
{ 
    IList<T> myIList = new List<T>(); 

    foreach(T item in list) 
    { 
    myIList.Add(item); 
    } 

    b.MethodB(myIList); 
} 

मुझे आशा है कि यह उपयोगी है।

2

समस्या आपके सिर को पाने के लिए एक मुश्किल है। DetailType ITypeEntity से प्राप्त हो सकता है, लेकिन वास्तव में ITypeEntity नहीं है। विस्तार प्रकार का आपका कार्यान्वयन अलग-अलग कार्यक्षमता पेश कर सकता है, इसलिए DetailType ITypeEntity लागू करता है लेकिन ITypeEntity के बराबर नहीं है। मुझे आशा है कि यह समझ में आता है ...

0

यदि बी ए का उप-वर्ग है, तो इसका मतलब यह नहीं है कि Class<B>Class<A> का उप-वर्ग है। इसलिए, इसी कारण से, यदि आप कहते हैं कि "T एक ITypeEntity है", इसका मतलब यह नहीं है कि "IRepo<T> एक IRepo<ITypeEntity> है"। यदि आप यह काम करना चाहते हैं तो आपको अपनी खुद की रूपांतरण विधि लिखनी पड़ सकती है।

0

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

0

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

3

वैसे यह ठीक है। मैंने मूल रूप से सामान्य पैरामीटर लेने के लिए कक्षाओं को फिर से परिभाषित किया। यह आपके संदर्भ में ठीक हो सकता है।

public interface IRepo<TRepo> 
{ 
} 

public interface ITypeEntity 
{ 
} 


public class ClassA<T> where T : ITypeEntity 
{ 
    ClassB<T> b = new ClassB<T>(); 
    public void MethodA(IRepo<T> repo) 
    { 
     b.MethodB(repo); 
    } 
} 
public class ClassB<T> where T : ITypeEntity 
{ 
    IRepo<T> repo; 
    public void MethodB(IRepo<T> repo) 
    { 
     this.repo = repo; 
    } 
} 
+0

आप प्रथम श्रेणी अप generic'ing रहे हैं 2 भी –

+0

generic'ed जा करने के लिए दुर्भाग्य से मैं ClassA एक सामान्य वर्ग बनाने के लिए विकल्प नहीं है यह एक एएसपी नेट उपयोगकर्ता के रूप में की आवश्यकता होगी नियंत्रण और मैं वास्तव में उस समस्या को समझने की कोशिश नहीं करना चाहता हूं। हालांकि आपके विचार के लिए धन्यवाद। मेरे द्वारा दिए गए सीमित संदर्भ के आधार पर यह बिल्कुल उचित था। –

+0

उस स्थिति में, क्या आपको जेनेरिक का उपयोग करने की आवश्यकता है? यह मुझे समस्या पर हमला करता है क्योंकि क्लासए में क्लासबी प्रकार का ऑब्जेक्ट होता है। पहले जेनरिक के बिना लागू करने की कोशिश करें - यह पर्याप्त हो सकता है। –

0

यह जेनरिक का एक अनावश्यक उपयोग है, यदि टी केवल आईटीपीईएनटीटी का एक उदाहरण हो सकता है तो आपको जेनिक्स का उपयोग नहीं करना चाहिए।

जेनेरिक तब होते हैं जब आपके पास कई प्रकार होते हैं जो कुछ के अंदर हो सकते हैं।

+0

यह बिल्कुल सही नहीं है। टी कोई ऑब्जेक्ट हो सकता है जो ITypeEntity लागू करता है। यह जेनेरिक का सही उपयोग है। – Metro

+0

हाँ, पर क्योंकि ITypeEntity एक अंतरफलक आप किसी भी बिंदु पर एक ITypeEntity वापस करने के लिए वस्तु डाल सकता है। तो वास्तव में उस सामान्य तर्क में कुछ पारित करने के लिए इसे ITypeEntity को लागू करना होगा, बदले में यह "is" ITypeEntity –

1

I get the following error: cannot convert from IRepo<'T> to IRepo<'ITypeEntity>

आप इस संकलन त्रुटि हो रही है क्योंकि IRepo<T> और IRepo<ITypeEntity> हैं नहीं एक ही बात कर रहे हैं। उत्तरार्द्ध पूर्व का एक विशेषज्ञ है।IRepo<T> एक सामान्य प्रकार परिभाषा, जहां प्रकार पैरामीटर टी एक प्लेसहोल्डर है है, और IRepo<ITypeEntity> सामान्य प्रकार परिभाषा है, जहां प्रकार पैरामीटर टी से ITypeEntity होने के लिए निर्दिष्ट किया जाता है की एक constructured सामान्य प्रकार है।

I keep thinking that this should compile as I'm constraining T within MethodA to be of type ITypeEntity.

where बाधा यहाँ मदद नहीं है क्योंकि यह केवल प्रकार आप MethodA के लिए कॉल-स्थलों पर टी के लिए प्रदान कर सकते हैं contrains है।

यहाँ MSDN प्रलेखीकरण से शब्दावली है (Generics in the .NET Framework देखें) मदद मिल सकती है:

  • एक सामान्य प्रकार परिभाषा एक वर्ग, संरचना, या इंटरफ़ेस घोषणा है कि एक टेम्पलेट के रूप में काम करता है, के साथ प्रकारों के लिए प्लेसहोल्डर जो इसमें शामिल हो या उपयोग कर सकते हैं। उदाहरण के लिए, Dictionary<<K, V> कक्षा में दो प्रकार हो सकते हैं: कुंजी और मान। क्योंकि यह केवल एक टेम्पलेट है, आप कक्षा, संरचना, या इंटरफ़ेस जो जेनेरिक प्रकार परिभाषा है, के उदाहरण बना सकते हैं।

  • जेनेरिक प्रकार पैरामीटर, या पैरामीटर टाइप करें, में प्लेसहोल्डर एक सामान्य प्रकार या विधि परिभाषा हैं। Dictionary<K, V> जेनेरिक प्रकार में दो प्रकार पैरामीटर, के और वी हैं, इसकी चाबियों के प्रकार और मानों का प्रतिनिधित्व करते हैं।

  • एक का निर्माण सामान्य प्रकार, या निर्माण प्रकार, एक सामान्य प्रकार परिभाषा के जेनेरिक प्रकार पैरामीटर के लिए को निर्दिष्ट प्रकार का परिणाम है।

  • एक सामान्य प्रकार का तर्क किसी भी प्रकार है जिसे सामान्य प्रकार पैरामीटर के लिए प्रतिस्थापित किया जाता है।

  • सामान्य शब्द सामान्य प्रकार में निर्मित प्रकार और सामान्य प्रकार की परिभाषाएं शामिल हैं।

  • बाधाएं जेनेरिक प्रकार पैरामीटर पर सीमाएं हैं। उदाहरण के लिए, आप IComparer<T> जेनेरिक इंटरफ़ेस को लागू करने वाले प्रकारों के लिए पैरामीटर को टाइप कर सकते हैं, ताकि यह सुनिश्चित किया जा सके कि प्रकार के उदाहरणों का आदेश दिया जा सके। आप प्रकारों को भी टाइप पैरामीटर को बाध्य कर सकते हैं जिनके पास विशेष आधार क्लास है, जिसमें डिफ़ॉल्ट कन्स्ट्रक्टर है, या संदर्भ प्रकार या मान प्रकार हैं। जेनेरिक प्रकार के उपयोगकर्ता तर्कों को प्रतिस्थापित नहीं कर सकते हैं जो बाधाओं को पूरा नहीं करते हैं।

1

कृपया देखें @monoxide के सवाल

और as I said there, जेनरिक के लिए contravariance और सहप्रसरण पर पदों की एरिक Lippert की श्रृंखला बाहर की जाँच के इस स्पष्ट का एक बहुत कर देगा।

0

सामान्य तरीकों चारों ओर अपने सिर लपेटकर के संदर्भ में, मैं आपको एक सरल सामान्य समारोह देने के लिए अनुमति देते हैं। यह वीबी के IIf() (तत्काल अगर), जो अपने आप सी-शैली त्रिगुट ऑपरेटर के एक गरीब नकली है की एक सामान्य बराबर है (?)। यह कुछ भी करने के लिए उपयोगी है क्योंकि असली त्रिगुट ऑपरेटर बेहतर है नहीं है, लेकिन शायद यह आप समझते हैं कि सामान्य समारोह निर्माण कर रहे हैं और क्या संदर्भों में वे लागू किया जाना चाहिए मदद मिलेगी।

T IIF<T>(bool Expression, T TruePart, T FalsePart) 
{ 
    return Expression ? TruePart : FalsePart; 
} 
संबंधित मुद्दे