在运行时创建类型"MyClass:OtherClass <MyClass> {}"?

wes*_*wes 9 c# generics reflection runtime

在C#中是否可以在运行时创建一个继承自泛型类的类型,其中基类的模板参数是正在构造的当前类?这将编译好:

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

// I want to create this at runtime:
public class MyClass : OtherClass<MyClass>
{ }
Run Code Online (Sandbox Code Playgroud)

但我不确定如何创建MyClass使用System.Reflection.Emit.ModuleBuilder.TypeBuilder:

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();
Run Code Online (Sandbox Code Playgroud)

这可能吗?

编辑 - 根据目前为止的回复,我试过这个:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但得到这个例外:

GenericArguments[0], 'MyClass', on 'MyProject.Factory+OtherClass`1[T]'
violates the constraint of type 'T'.
Run Code Online (Sandbox Code Playgroud)

gra*_*hus 7

编辑:这是我最后的工作答案:

        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);
Run Code Online (Sandbox Code Playgroud)

诀窍是使用参数化泛型类型调用SetParent,该参数是正在构造的类型的类型构建器.


使用TypeBuilder.SetParent(Type父类)方法.

使用它时要小心,异常抛出会延迟CreateType调用:

如果parent为null,则将Object用作基本类型.

在.NET Framework 1.0和1.1版中,如果parent是接口类型,则不会引发异常,但在调用CreateType方法时会抛出TypeLoadException.

SetParent方法不检查大多数无效的父类型.例如,当当前类型具有默认构造函数时,它不拒绝没有默认构造函数的父类型,它不拒绝密封类型,并且它不拒绝委托类型.在所有这些情况下,CreateType方法抛出异常.

要构建泛型类型OtherClass<T>,请使用MakeGenericType方法:

var genericType = typeof(OtherClass<>).MakeGenericType(typeof(MyClass));
Run Code Online (Sandbox Code Playgroud)