2012-03-20 9 views
5

सामान्य प्रकार क्यों नहीं खोल सकते पैरामीटर के रूप में पारित किया जा सकता है। मेरे पास अक्सर कक्षाएं होती हैं:सी # सामान्य प्रकार क्यों नहीं खोल सकते पैरामीटर के रूप में पारित किया जा सकता है?

public class Example<T> where T: BaseClass 
{ 
    public int a {get; set;} 
    public List<T> mylist {get; set;} 
} 

आइए बेसक्लस निम्नानुसार है; सिर्फ एक पैरामीटर के रूप में यह एक वर्ग पारित करने के लिए

public int MyArbitarySumMethod(Example example)//This won't compile Example not closed 
{ 
    int sum = 0; 
    foreach(BaseClass i in example.myList)//myList being infered as an IEnumerable 
     sum += i.num; 
    sum = sum * example.a; 
    return sum; 
} 

मैं तो एक इंटरफेस लिखने के लिए है इस प्रकार है::

public BaseClass 
{ 
    public int num; 
} 

मैं तो कहते हैं की एक विधि चाहते

public interface IExample 
{ 
public int a {get; set;} 
public IEnumerable<BaseClass> myIEnum {get;} 
} 

सामान्य कक्षा को तब संशोधित किया जाना चाहिए:

public class Example<T>: IExample where T: BaseClass 
{ 
    public int a {get; set;} 
    public List<T> mylist {get; set;} 
    public IEnumerable<BaseClass> myIEnum {get {return myList;} } 
} 

यह एक बहुत ही समारोह है जो मैंने सोचा था कि संकलक अनुमान लगा सकता है। यहां तक ​​कि अगर कुछ नहीं बदला जा सकता है, तो मुझे सिंटैक्स शॉर्ट कट्स की अनुपस्थिति के कारणों/औचित्य के बारे में पता है, तो मुझे मनोवैज्ञानिक रूप से बहुत उपयोगी लगता है।

+3

यह वास्तव में स्पष्ट नहीं है कि आप किस प्रतिबंध के बारे में बात कर रहे हैं, क्योंकि आपने यह नहीं दिखाया है कि आप इसे कैसे पारित करने का प्रयास कर रहे हैं। मुझे * संदेह है * मुझे पता है कि आपका क्या मतलब है, लेकिन सवाल स्पष्ट नहीं है ... –

+0

जब आप "सामान्य प्रकार कैसे खोलें" पूछते हैं तो आपका क्या मतलब है? –

+0

@Rich, यदि आप 'टी' अनिर्दिष्ट बने रहे हैं, तो आप 'उदाहरण ' (सिद्धांत रूप में भी) को वाक्यबद्ध रूप से कैसे पारित करेंगे? –

उत्तर

2

मैं इसी तरह की स्थिति में रहा हूं, लेकिन मुझे यह कभी नहीं मिला (बहुत अच्छा!) प्रश्न।

आप उम्मीद काम करने के लिए निम्नलिखित:

void F(Example<> e) { 
    Console.WriteLine(e.a); //could work 
} 

हाँ, यह सैद्धांतिक रूप से काम कर सकता है, लेकिन यह ऐसा नहीं करेंगे: अब जब कि मैं इसके बारे में सोचने के लिए मजबूर कर रहा हूँ, यहाँ मेरा उत्तर है

void F(Example<> e) { 
    Console.WriteLine(e.mylist); //?? type unknown 
} 

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

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

+1

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

+0

मेरा अनुभव मुझे बताता है कि यह कभी-कभी होता है, लेकिन शायद ही कभी। निश्चित रूप से, यह पूरी तरह से परियोजना पर निर्भर करता है। लेकिन मेरा मुख्य बिंदु वास्तव में यह है कि यह सुविधा शायद भ्रमित हो रही है ("मैं क्यों एक्सेस कर सकता हूं लेकिन मेरी सूची नहीं?" "यह क्यों काम करता है लेकिन वह नहीं?") और यह कि एक अच्छा समाधान ढूंढना संभव नहीं है जो काम करता है बिल्कुल सभी मामलों। – usr

+0

शायद मैं सामान्य सी # कोड नहीं लिखता हूं। मुझे रात के अंधेरे घंटों में कबूल करना चाहिए, विचार स्मॉलटाक और लिस्प ने मेरे दिमाग को पार कर लिया है। –

2

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

+0

वास्तव में, स्थिति उससे भी बदतर है। यदि 'Foo ' उदा। एक स्थिर क्षेत्र 'बार' प्रकार 'int',' Foo .'', 'Foo .बार', 'Foo .बार', 'Foo बार', आदि सभी अलग-अलग संग्रहण स्थानों का संदर्भ लेंगे जो अलग-अलग मूल्य हो सकते हैं। उनमें से कौन सा 'Foo <> बार' संदर्भित करेगा? चूंकि कोई तरीका सामान्य तरीका नहीं है कि कुछ 'Foo ' पर कुछ सदस्य को कॉल करने वाला एक कंपाइलर यह बताने में सक्षम होगा कि वह सदस्य सीधे या अप्रत्यक्ष रूप से 'Foo "तक पहुंच सकता है या नहीं, इसका कोई तरीका नहीं होगा कि कॉल करने का कोई प्रयास है या नहीं पैरामीटर के बिना 'Foo <>' संभवतः सुरक्षित हो सकता है। – supercat

1

शायद मैं ठीक आपके प्रश्न समझ नहीं कर रहा हूँ, लेकिन आप कर सकते हैं अपने "MyArbitrarySumMethod" इस तरह यह घोषणा करके एक मनमाना उदाहरण लेते हैं:

public int MyArbitarySumMethod<T>(Example<T> example) where T : BaseClass 

फिर आप यह "टी" निर्दिष्ट किए बिना कॉल कर सकते हैं:

int sum = MyArbitrarySumMethod(myExampleInstance); 

क्या आप यही देख रहे हैं?

+0

@ किर्कवॉल: नहीं, मुझे ऐसा नहीं लगता है। यह दृष्टिकोण बिल्कुल वही है जिसे मैं सुझाव देने जा रहा था। –

+0

@ जोन, मुझे लगता है कि आप सही हैं। मुझे लगता था कि ओपी 'टी' के संदर्भ के बिना एक सामान्य प्रकार को पास करने के लिए एक सामान्य तरीका ढूंढ रहा था - जहां सामान्य समाधान * इसके लिए एक इंटरफेस-रैपर लिखने के लिए है। लेकिन किसी विधि के विशिष्ट उपयोग-मामले के लिए, आप सही हैं कि यह काम करेगा। –

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

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