2012-07-11 14 views
10

मैंने सोचा था कि जेनिक्स इन सी # को इस तरह कार्यान्वित किया गया था कि एक नई कक्षा/विधि/जो-आप-उत्पन्न हुई थी, या तो रन-टाइम या संकलन-समय पर, जब एक नया सामान्य प्रकार का उपयोग किया गया था, सी ++ टेम्पलेट्स के समान (जिसे मैंने वास्तव में कभी नहीं देखा है और मैं बहुत अच्छा हो सकता हूं, जिसके बारे में मैं खुशी से सुधार स्वीकार करता हूं)।सी # जेनेरिक कैसे लागू किए जाते हैं?

static class Program { 
    static void Main() 
    { 
     Test testVar = new Test(); 

     GenericTest<Test> genericTest = new GenericTest<Test>(); 
     int gen = genericTest.Get(testVar); 

     RegularTest regTest = new RegularTest(); 
     int reg = regTest.Get(testVar); 

     if (gen == ((object)testVar).GetHashCode()) 
     { 
      Console.WriteLine("Got Object's hashcode from GenericTest!"); 
     } 
     if (reg == testVar.GetHashCode()) 
     { 
      Console.WriteLine("Got Test's hashcode from RegularTest!"); 
     } 
    } 

    class Test 
    { 
     public new int GetHashCode() 
     { 
      return 0; 
     } 
    } 

    class GenericTest<T> 
    { 
     public int Get(T obj) 
     { 
      return obj.GetHashCode(); 
     } 
    } 

    class RegularTest 
    { 
     public int Get(Test obj) 
     { 
      return obj.GetHashCode(); 
     } 
    } 
} 
उन सांत्वना लाइनों प्रिंट की

दोनों:

लेकिन मेरे कोडिंग में मैं एक सटीक counterexample के साथ आया था।

मुझे पता है कि वास्तविक कारण यह होता है कि ऑब्जेक्ट.गेटहाशकोड() को वर्चुअल कॉल टेस्ट.गेटहाशकोड() को हल नहीं करता है क्योंकि टेस्ट में विधि को ओवरराइड के बजाय नए के रूप में चिह्नित किया जाता है। इसलिए, मुझे पता है कि मैंने टेस्ट पर "नया" के बजाय "ओवरराइड" का उपयोग किया था। गेटशैशकोड() तो 0 की वापसी पॉलिमॉर्फिक विधि में GetHashCode विधि को ओवरराइड करेगा और यह सच नहीं होगा, लेकिन मेरी (पिछली) समझ के अनुसार सी # जेनेरिकों में यह mattered नहीं होगा क्योंकि टी के हर उदाहरण टेस्ट के साथ बदल दिया गया होगा, और इस प्रकार विधि कॉल स्थिर रूप से (या सामान्य संकल्प समय पर) "नई" विधि के लिए हल किया गया होगा।

तो मेरा प्रश्न यह है: सी # में जेनेरिक कैसे लागू किए जाते हैं? मुझे सीआईएल बाइटकोड नहीं पता है, लेकिन मुझे जावा बाइटकोड पता है, इसलिए मैं समझता हूं कि ऑब्जेक्ट उन्मुख सीएलआई भाषाएं निम्न स्तर पर कैसे काम करती हैं। उस स्तर पर व्याख्या करने के लिए स्वतंत्र महसूस करें।

एक के रूप में अलग रूप में, मैंने सोचा था कि क्योंकि हर कोई हमेशा सी # में जेनेरिक प्रणाली "ट्रू जेनेरिक्स," जावा के प्रकार-विलोपन प्रणाली की तुलना में कॉल सी # जेनरिक कि जिस तरह से लागू किया गया।

+0

यहां 'gen == ((ऑब्जेक्ट) testVar ऑब्जेक्ट करने के लिए डालने का कोई कारण) .GetHashCode()'? – AlwaysAProgrammer

+0

हालांकि यह सीधे आपके प्रश्न का उत्तर नहीं देता है, http://blogs.msdn.com/b/ericlippert/archive/2012/07/10/when-is-a-cast-not-a-cast.aspx कुछ अच्छा है जेनेरिक कैसे डाले जाते हैं और सी # में एक-दूसरे से कैसे संबंधित होते हैं, इस बारे में जानकारी। – devstruck

+0

@Yogendra ऐसा तक पहुँचता है 'नई' विधि Test.GetHashCode() विधि के बजाय Object.GetHashCode()। यही कारण है कि यह एक अलग मूल्य देता है (क्योंकि यह पूरी तरह से एक अलग विधि चलाता है)। – Carrotman42

उत्तर

7

GenericTest<T>.Get(T) में, सी # संकलक पहले से ही उठाया कि object.GetHashCode (लगभग) बुलाया जाना चाहिए है। रनटाइम पर "नई" GetHashCode विधि को हल करने का कोई तरीका नहीं है (object.GetHashCode के लिए स्लॉट को ओवरराइड करने के बजाय विधि-तालिका में अपना स्वयं का स्लॉट होगा)।

एरिक Lippert के What's the difference, part one: Generics are not templates से, इस मुद्दे को समझाया गया है (प्रयुक्त सेटअप थोड़ा अलग है, लेकिन सबक अपने परिदृश्य के लिए अच्छी तरह से अनुदित):

यह दिखाता है कि सी # में जेनरिक सी में टेम्पलेट्स की तरह नहीं हैं ++। तुम एक फैंसी-पैंट के रूप में टेम्पलेट्स के बारे में सोच सकते खोज एवं प्रतिस्थापन तंत्र [...] कि कैसे सामान्य प्रकार के काम नहीं है।; जेनेरिक प्रकार हैं, अच्छी तरह से, जेनेरिक। हम अधिभार संकल्प एक बार करते हैं और परिणाम में सेंकना करते हैं। [...] जेएलआई जेनेरिक प्रकार के लिए जेनरेट किया गया है, पहले से ही विधि को कॉल करने जा रहा है। घबराना नहीं कहती "ठीक है, मुझे पता है कि यह अतिरिक्त जानकारी तो यह एक अलग अधिभार उठाया है | साथ निष्पादित करने के लिए अगर हम सी # संकलक पूछा अभी होता है। मुझे कोड है कि सी # संकलक मूल रूप से उत्पन्न की अनदेखी करने के तैयार किए गए कोड को फिर से लिखने दें ... "घबराना सी # के नियमों के बारे में कुछ नहीं जानता ।

और अपने वांछित अर्थ विज्ञान के लिए एक वैकल्पिक हल:

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

+3

आह एरिक, जो कुछ भी हम तुम्हारे बिना करना होगा। – Servy

+0

हाँ, मैंने कहा कि पैरा के साथ शुरू में "मुझे पता है कि वास्तविक कारण ऐसा होता है ... कि" कि मेरे सवाल था "सी # जेनेरिक्स कार्यान्वित किया जाता है कैसे?" मैं आपके द्वारा भेजे गए लिंक को पढ़ूंगा, शायद यह मेरे प्रश्न का उत्तर देगा। – Carrotman42

+0

@ आपका संपादन: ऐसा नहीं है कि मैं यह करना चाहता हूं: मैं जावा की पृष्ठभूमि से आया हूं जहां यह पूरी "नई विधि" परीक्षा मौजूद नहीं है। मुझे लगता है कि यह उपयोगकर्ता त्रुटि के लिए प्रवण है और मैं इसे उद्देश्य पर कभी भी इस्तेमाल करने की योजना नहीं बना रहा हूं। कारण मैं इसमें भाग गया क्योंकि मैं एक अमूर्त वर्ग लिख रहा था जहां मैं सबक्लास को गेटहाशकोड लागू करने के लिए मजबूर करना चाहता था, इसलिए मैंने "सार्वजनिक अमूर्त int GetHashcode();" यह महसूस नहीं किया कि यह काम किसी भी चीज़ के साथ करने के लिए बुला GetHashCode सामान्य रूप से मैं वास्तव में कहना था "सार्वजनिक ओवरराइड सार पूर्णांक GetHashcode();" है, जो मेरी पसंद के लिए बहुत वर्बोज़ है। – Carrotman42

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