简体   繁体   English

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

[英]Create type “MyClass : OtherClass<MyClass> { }” at runtime?

Is it possible in C# to create a type at runtime that inherits from a generic class where the template parameter for the base class is the current class being constructed? 在C#中,是否有可能在运行时创建从通用类继承的类型,在该通用类中,基类的模板参数是正在构造的当前类? This will compile fine: 这样可以编译良好:

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

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

but I'm not sure how to create the MyClass using System.Reflection.Emit.ModuleBuilder.TypeBuilder : 但是我不确定如何使用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();

Is this possible? 这可能吗?

Edit - Based on replies so far, I've tried this: 编辑-根据到目前为止的答复,我已经尝试过:

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;
    }
}

but get this exception: 但是得到这个异常:

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

Edit : Here is my final working answer : 编辑:这是我最后的工作答案:

        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);

The trick is to call SetParent with a parametrised generic type, the parameter is the typebuilder of the type being constructed itself. 诀窍是使用参数化的泛型类型调用SetParent,该参数是正在构造的类型本身的类型构建器。


Use the TypeBuilder.SetParent(Type parent) method. 使用TypeBuilder.SetParent(Type parent)方法。

Be careful when using it, exception throwing is deferred to CreateType call : 使用它时要小心,将异常抛出推迟到CreateType调用:

If parent is null, Object is used as the base type. 如果parent为null,则将Object用作基本类型。

In the .NET Framework versions 1.0 and 1.1, no exception is thrown if parent is an interface type, but a TypeLoadException is thrown when the CreateType method is called. 在.NET Framework版本1.0和1.1中,如果parent是接口类型,则不会引发异常,但是在调用CreateType方法时,会引发TypeLoadException。

The SetParent method does not check for most invalid parent types. SetParent方法不检查大多数无效的父类型。 For example, it does not reject a parent type that has no default constructor when the current type has a default constructor, it does not reject sealed types, and it does not reject the Delegate type. 例如,当当前类型具有默认构造函数时,它不拒绝没有默认构造函数的父类型,不拒绝密封类型,也不拒绝委托类型。 In all these cases, exceptions are thrown by the CreateType method. 在所有这些情况下,CreateType方法都会引发异常。

To build your generic type OtherClass<T> , use the MakeGenericType method : 要构建通用类型OtherClass<T> ,请使用MakeGenericType方法:

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

You can set the base type afterwards. 之后可以设置基本类型。

TypeBuilder.SetParent(Type) TypeBuilder.SetParent(类型)

Yes. 是。 Its possible. 这是可能的。 See Reflection.Emit namespace and TypeBuilder`s methods. 请参见Reflection.Emit名称空间和TypeBuilder的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM