2011-01-26 11 views
9

से सदस्य कार्यान्वयन के प्रयोग से। मैंने सी # में निम्नलिखित कोड संकलित किया और सी # कंपाइलर क्या करता है यह देखने के लिए परावर्तक में इसकी जांच की।नेट एक अंतरफलक को लागू करने में एक DynamicType बनाना, लेकिन मैं एक अंतरफलक को लागू करने के लिए एक गतिशील वर्ग उत्पन्न करने के लिए प्रयास कर रहा हूँ, लेकिन जहां एक या सदस्यों की अधिक पहले से ही आधार में मौजूद है एक आधार वर्ग

class BaseClass 
{ 
    public string Bob 
    { 
     get { return "Bob"; } 
    } 
} 

interface IStuff 
{ 
    string Bob { get; } 
} 

class SubClass : BaseClass, IStuff 
{ 
} 

परावर्तक SubClass में कोई कार्यान्वयन नहीं दिखाता है।

.class private auto ansi beforefieldinit SubClass 
    extends Enterprise.Services.OperationalActions.Business.Filters.BaseClass 
    implements Enterprise.Services.OperationalActions.Business.Filters.IStuff 
{ 
} 

लेकिन अगर मैं सदस्य स्पष्ट रूप से फेंकना नहीं है, TypeBuilder.CreateType() एक InvalidOperationException करते हुए कहा कि सदस्य एक कार्यान्वयन नहीं है फेंकता है। तो मेरा सवाल यह है कि, मैं टाइपबिल्डर को कैसे बता सकता हूं कि एक इंटरफ़ेस सदस्य को आधार से इसका कार्यान्वयन करना चाहिए?

+3

आपका कोड नमूना यह नहीं दिखाता है कि 'सबक्लास' 'ISTuff' लागू करता है। क्या आप 'क्लास सबक्लास: बेस क्लास, आईएसटफ' लिखना चाहते थे? –

+0

ओह, याद किया कि। धन्यवाद। –

उत्तर

6

ऐसा लगता है कि TypeBuilder साथ की तरह आप एक निजी पास होना जोड़ना होगा बस खुश (नीचे) बनाने के लिए। आप IKVM बिल्डर का उपयोग करने का भी प्रयास कर सकते हैं - लगभग समान API, लेकिन इसमें यह सीमा नहीं हो सकती है।

using System; 
using System.Reflection; 
using System.Reflection.Emit; 
public class BaseClass 
{ 
    public string Bob 
    { 
     get { return "Bob"; } 
    } 
} 

public interface IStuff 
{ 
    string Bob { get; } 
} 
static class Program 
{ 
    static void Main() 
    { 
     var name = new AssemblyName("foo"); 
     var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); 
     var mod = asm.DefineDynamicModule("foo"); 
     var parent = typeof(BaseClass); 
     var type = mod.DefineType("SubClass", parent.Attributes, parent); 
     type.AddInterfaceImplementation(typeof(IStuff)); 

     var bob_get = type.DefineMethod("bob_get", MethodAttributes.Virtual | MethodAttributes.Private, 
      typeof(string), Type.EmptyTypes); 
     var il = bob_get.GetILGenerator(); 
     il.Emit(OpCodes.Ldarg_0); 
     il.EmitCall(OpCodes.Callvirt, parent.GetProperty("Bob").GetGetMethod(), null); 
     il.Emit(OpCodes.Ret); 
     type.DefineMethodOverride(bob_get, typeof(IStuff).GetProperty("Bob").GetGetMethod()); 
     var final = type.CreateType(); 
     IStuff obj = (IStuff) Activator.CreateInstance(final); 
     Console.WriteLine(obj.Bob); 
    } 
} 
+0

धन्यवाद, यह दुर्भाग्यपूर्ण है कि मुझे एक रैपर संपत्ति की आवश्यकता है लेकिन यह अभी भी मेरी ज़रूरतों के लिए पर्याप्त होना चाहिए। –

5

सी # संकलक वास्तव में पर कि क्या आपके SubClass परिभाषा एक ही विधानसभा में है या नहीं निर्भर करता है BaseType के लिए अलग अलग कोड का उत्सर्जन करता है। तो तुम सिर्फ इस अगर:

interface IStuff 
{ 
    string Bob { get; } 
} 

public class BaseClass 
{ 
    public string Bob 
    { 
     get { return "Bob"; } 
    } 
} 

और फिर एक और सी # परियोजना में SubClass परिभाषित करते हैं, तो संकलक में वाकई एक स्पष्ट इंटरफेस कार्यान्वयन फेंकना होगा। ऐसा इसलिए है क्योंकि इस मामले में, BaseClass.get_Bob को गैर-वर्चुअल के रूप में परिभाषित किया जाएगा, जिसका अर्थ है कि इसका उपयोग इंटरफ़ेस के अनुबंध को पूरा करने के लिए नहीं किया जा सकता है।

भी Why are C# interface methods not declared abstract or virtual?, जो स्पष्ट रूप से जवाब के अंत में इस विषमता की चर्चा देखें।

+0

मैंने सोचा होगा कि इंटरफ़ेस के लिए vtable रिकॉर्ड बेसक्लास द्वारा कार्यान्वयन को इंगित करेगा। जब मैं इस शाम को घर जाता हूं तो मुझे लिंक पर जाना होगा, ऐसा लगता है कि यह दिलचस्प हो सकता है। –

+0

@ ब्रायन - मेरा मानना ​​है कि केवल वर्चुअल विधियां उपclasses विधि तालिकाओं के भीतर लगातार स्लॉट में दिखाई देती हैं। तो इंटरफ़ेस के लिए 'बेसक्लास' की विधि तालिका में एक स्लॉट को इंगित करने के लिए जो उप-वर्गों के लिए भी काम करेगा, विधि वर्चुअल होना चाहिए, यही कारण है कि आईएल में सभी इंटरफ़ेस विधि कार्यान्वयन वर्चुअल होना चाहिए (हालांकि सी # कंपाइलर नहीं है आपको उन्हें इस तरह एनोटेट करने की आवश्यकता है)। – kvb

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