2012-04-10 45 views
10

Tôi cần tạo một lớp động. Hầu hết mọi thứ hoạt động tốt nhưng tôi đang mắc kẹt trong việc tạo ra các nhà xây dựng.Tự động tạo kiểu và gọi hàm tạo của lớp cơ sở

AssemblyBuilder _assemblyBuilder = 
     AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("MyBuilder"),              AssemblyBuilderAccess.Run); 

ModuleBuilder _moduleBuilder = _assemblyBuilder.DefineDynamicModule("MyModule"); 

public static object GetInstance<TSource, TEventArgs>(this TSource source, string eventName) 
    where TSource : class 
{ 
    var typeName = "MyTypeName"; 
    var typeBuilder = _moduleBuilder.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Public); 

    // create type like class MyClass : GenericType<MyClass, TSource, TEventArgs> 
    var baseNotGenericType = typeof(GenericType<,,>); 
    var baseType = baseNotGenericType.MakeGenericType(typeBuilder, typeof(TSource), typeof(TEventArgs)); 
    typeBuilder.SetParent(baseType); 


    // the base class contains one constructor with string as param 
    var baseCtor = baseNotGenericType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(string) }, null); 

    var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard | CallingConventions.HasThis, new Type[0]); 
    var ilGenerator = ctor.GetILGenerator(); 

    // i want to call the constructor of the baseclass with eventName as param 
    ilGenerator.Emit(OpCodes.Ldarg_0); // push "this" 
    ilGenerator.Emit(OpCodes.Ldstr, eventName); // push the param 
    ilGenerator.Emit(OpCodes.Call, baseCtor); 
    ilGenerator.Emit(OpCodes.Ret); 

    var type = typeBuilder.CreateType(); 

    // return ... 
} 

Khi gọi hàm tạo, tôi nhận được BadImageFormatException. Tôi đang làm gì sai?

Theo yêu cầu:

Các BaseClass trông giống như sau:

public abstract class GenericType<GT, TEventSource, TEventArgs> : BaseClass 
    where GT: GenericType<GT, TEventSource, TEventArgs>, new() 
    where TEventArgs : EventArgs 
    where TEventSource : class 
{ 
    protected GenericType(string eventName) 
    { 
     _eventName = eventName; 
    } 
    // ... 
} 

gì tôi muốn có kết quả là trong thời gian chạy:

public class MyType : BaseClass<MyType, ConcreteSourceType, ConcreteEventArgsType> 
{ 
    protected MyType() : base("SomeName") 
    { 

    } 
} 
+0

có một cái nhìn ở đây http://stackoverflow.com/questions/893423/how-do-create-a-dynamic-class-in-c-sharp-4 –

+0

Không thực sự hữu ích hoặc đã làm tôi bỏ lỡ một cái gì đó? Tôi muốn kế thừa từ một baseclass và gọi nó là constructor cơ sở mà có một đối số. – SACO

+0

Hãy thử liên kết này cũng http://blogs.msdn.com/b/cburrows/archive/2009/04/22/dynamic-base-classes-in-c-4.aspx –

Trả lời

10

Tôi nghĩ vấn đề là bạn đang cố gọi hàm khởi tạo của kiểu generic mở GenericType<GT, TEventSource, TEventArgs>, nhưng bạn cần gọi hàm khởi tạo của kiểu đóng BaseClass<MyType, ConcreteSourceType, ConcreteEventArgsType>. Giải pháp cho dường như đơn giản:

var baseCtor = baseType.GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Instance, null, 
    new[] { typeof(string) }, null); 

Vấn đề là điều này không hoạt động và ném NotSupportedException. Vì vậy, có vẻ như nhận được hàm tạo của một kiểu chung, trong đó một trong các tham số là một TypeBuilder là hạt được hỗ trợ.

Vì lý do đó, tôi nghĩ rằng những gì bạn muốn là không thể sử dụng Reflection.Emit, trừ khi có một số hack để làm việc xung quanh này.

EDIT: A-HA! Tôi phải lặn sâu vào Reflection.Emit trong Reflector (mặc dù nhìn vào đúng vị trí trong tài liệu cũng đã hoạt động), nhưng tôi thấy nó: có một phương pháp đặc biệt chính xác cho điều này: the static TypeBuilder.GetConstructor(). Vì vậy, điều này sẽ làm việc:

var baseNonGenericCtor = baseNotGenericType.GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Instance, null, 
    new[] { typeof(string) }, null); 
var baseCtor = TypeBuilder.GetConstructor(baseType, baseNonGenericCtor); 
+0

Vì vậy, tôi mong nhìn thấy một hack :) – SACO

+0

Trên thực tế, nó là có thể và nó không phải là một hack ở tất cả, xem chỉnh sửa. – svick

+0

BTW, những câu hỏi như thế này khiến tôi học được điều gì đó mới mẻ là tốt nhất. – svick

3

Cách đơn giản nhất để làm điều này sẽ được biên dịch lên lớp trừu tượng và nguồn gốc của bạn thành một lắp ráp đơn giản, sau đó mở chúng trong suy nghi sử dụng "Reflection.Emit" ngôn ngữ có sẵn như là một addin từ:

http://reflectoraddins.codeplex.com/

Reflector: Reflection.Emit language

Vâng, đó là mát mẻ như nó có vẻ :)

+0

Bạn có chắc chắn nó sẽ làm việc trong trường hợp cụ thể này? – svick

+0

Nếu định nghĩa lớp mong muốn của bạn là hợp lệ C# và sẽ biên dịch, thì có. – x0n

+0

Vâng, mã nó tạo ra trong trường hợp này không có ý nghĩa nhiều và sẽ không giúp OP. Đó là bởi vì nó sử dụng 'typeof (MyType)', điều này không có ý nghĩa khi bạn đang xây dựng kiểu đó. Và bằng cách sử dụng 'typeBuilder' thay vào đó sẽ dẫn đến một' NotSupportedException'. – svick

Các vấn đề liên quan