2012-11-07 15 views
8

क्या सी # में रनटाइम पर एक प्रकार का निर्माण करना संभव है जो सामान्य वर्ग से विरासत में मिलता है जहां बेस क्लास के लिए टेम्पलेट पैरामीटर वर्तमान वर्ग का निर्माण किया जा रहा है? यह ठीक संकलन होगा:रनटाइम पर "MyClass: OtherClass <MyClass> {}" टाइप करें?

// I have this class: 
public class OtherClass<T> 
    where T : OtherClass<T> 
{ } 

// I want to create this at runtime: 
public class MyClass : OtherClass<MyClass> 
{ } 

लेकिन मुझे यकीन नहीं कर रहा हूँ कैसे System.Reflection.Emit.ModuleBuilder.TypeBuilder का उपयोग कर MyClass बनाने के लिए:

AssemblyName asn = new AssemblyName("test.dll"); 
AssemblyBuilder asb = AppDomain.CurrentDomain.DefineDynamicAssembly(
    asn, AssemblyBuilderAccess.RunAndSave, @"D:\test_assemblies"); 

ModuleBuilder = modb = asb.DefineDynamicModule("test", "test.dll"); 

TypeBuilder tb = modb.DefineType(
    "test", 
    TypeAttributes.Public | TypeAttributes.Class, 
    typeof(MyClass)); // How to specify inheritance? 

// populate properties, fields, methods, etc., emit... 

tb.CreateType(); 

यह संभव है?

संपादित करें - उत्तर के आधार पर अब तक, मैं इस कोशिश की है:

public class OtherClass<T> 
    where T : OtherClass<T> 
{ } 

public static void CreateSimple() 
{ 
    AssemblyName asn = new AssemblyName("test"); 
    AssemblyBuilder asb = AppDomain.CurrentDomain.DefineDynamicAssembly(
     asn, AssemblyBuilderAccess.RunAndSave, @"D:\test_asms"); 
    ModuleBuilder modb = asb.DefineDynamicModule("test", "test.dll"); 

    try 
    { 
     TypeBuilder tb = modb.DefineType(
      "MyClass", 
      TypeAttributes.Public | TypeAttributes.Class); 

     Type my = tb.CreateType(); 
     tb.SetParent(typeof(OtherClass<>).MakeGenericType(my)); 

     my = tb.CreateType(); 
    } 
    catch (Exception e) 
    { 
     throw; 
    } 
} 

लेकिन यह अपवाद:

GenericArguments[0], 'MyClass', on 'MyProject.Factory+OtherClass`1[T]' 
violates the constraint of type 'T'. 
+2

लेकिन ... क्यों आप इस करना होगा? – LightStriker

+0

@LightStriker: क्योंकि 99% 'MyClass' प्रकार कोड में परिभाषित किए गए हैं, लेकिन तैनाती (एनएचबीरनेट मॉडल) और 'अन्य क्लास' के बाद कुछ बनाने की आवश्यकता है, यह प्रतिबंधित करता है कि जेनेरिक प्रकार 'अन्य क्लास' से प्राप्त होता है। – wes

+0

मैंने अपना जवाब संपादित किया - यह जेनेरिकअर्गमेंट अपवाद के बिना अब काम करेगा। – gracchus

उत्तर

6

संपादित करें: यहाँ मेरा अंतिम काम कर जवाब है:

 AssemblyName asn = new AssemblyName("test.dll"); 
     AssemblyBuilder asb = AppDomain.CurrentDomain.DefineDynamicAssembly(
      asn, AssemblyBuilderAccess.RunAndSave, @"D:\test_assemblies"); 

     ModuleBuilder modb = asb.DefineDynamicModule("test", "test.dll"); 

     TypeBuilder tb = modb.DefineType(
      "test", 
      TypeAttributes.Public | TypeAttributes.Class); 
     // Typebuilder is a sub class of Type 
     tb.SetParent(typeof(OtherClass<>).MakeGenericType(tb)); 
     var t2 = tb.CreateType(); 
     var i = Activator.CreateInstance(t2); 

चाल एक parametrised सामान्य प्रकार के साथ SetParent कॉल करने के लिए है, पैरामीटर प्रकार की typebuilder ही निर्माण किया जा रहा है।


TypeBuilder.SetParent(Type parent) विधि का उपयोग करें।

सावधान जब इसे का उपयोग हो सकता है, अपवाद फेंक CreateType कॉल के लिए स्थगित किया गया है:

तो माता-पिता रिक्त है, वस्तु आधार प्रकार के रूप में प्रयोग किया जाता है।

.NET Framework संस्करण 1.0 और 1.1 में, यदि कोई इंटरफ़ेस प्रकार इंटरफ़ेस प्रकार है तो कोई अपवाद नहीं फेंक दिया गया है, लेकिन CreateType विधि को दबाए जाने पर TypeLoadException फेंक दिया जाता है।

SetParent विधि सबसे अमान्य पैरेंट प्रकारों की जांच नहीं करता है। उदाहरण के लिए, यह किसी ऐसे मूल प्रकार को अस्वीकार नहीं करता है जिसमें वर्तमान प्रकार का डिफॉल्ट कंस्ट्रक्टर होता है, तो यह कोई डिफ़ॉल्ट कन्स्ट्रक्टर नहीं होता है, यह सीलबंद प्रकारों को अस्वीकार नहीं करता है, और यह प्रतिनिधि प्रकार को अस्वीकार नहीं करता है। इन सभी मामलों में, CreateType विधि द्वारा अपवाद फेंक दिए जाते हैं।

अपने सामान्य प्रकार OtherClass<T> बनाने के लिए, MakeGenericType विधि का उपयोग करें:

var genericType = typeof(OtherClass<>).MakeGenericType(typeof(MyClass)); 
+0

मैंने इसे शामिल करने के लिए अपनी पोस्ट संपादित की है।दुर्भाग्यवश मुझे एक अपवाद मिला कि 'माइक्लास' ने टाइप 'टी' की बाधा का उल्लंघन किया। – wes

+1

यह करता है! धन्यवाद! – wes

1

हां। यह संभव है। Reflection.Emit नामस्थान और टाइपबिल्डर की विधियां देखें।

+0

वह पहले से ही प्रतिबिंब का उपयोग कर रहा है। प्रवेश करें। आप सवाल समझ में नहीं आया। – leppie