9

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

しかし、私は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();

これは可能ですか?

編集-これまでの返信に基づいて、私はこれを試しました:

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'.
4

3 に答える 3

8

編集:これが私の最終的な答えです:

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

秘訣は、パラメーター化されたジェネリック型を使用してSetParentを呼び出すことです。パラメーターは、それ自体が構築されている型のタイプビルダーです。


TypeBuilder.SetParent(Type parent)メソッドを使用します。

使用するときは注意してください。例外のスローは呼び出しに延期されCreateTypeます:

親がnullの場合、オブジェクトが基本タイプとして使用されます。

.NET Frameworkバージョン1.0および1.1では、親がインターフェイスタイプの場合は例外はスローされませんが、CreateTypeメソッドが呼び出されるとTypeLoadExceptionがスローされます。

SetParentメソッドは、ほとんどの無効な親タイプをチェックしません。たとえば、現在の型にデフォルトコンストラクタがある場合、デフォルトコンストラクタのない親型を拒否せず、封印された型を拒否せず、Delegate型を拒否しません。これらすべての場合において、例外はCreateTypeメソッドによってスローされます。

ジェネリック型を作成するには、 MakeGenericTypeメソッドOtherClass<T>を使用します。

var genericType = typeof(OtherClass<>).MakeGenericType(typeof(MyClass));
于 2012-11-07T19:16:20.317 に答える
2

後で基本タイプを設定できます。

TypeBuilder.SetParent(Type)

于 2012-11-07T19:08:10.920 に答える
1

はい。それが可能だ。Reflection.Emit名前空間とTypeBuilderのメソッドを参照してください。

于 2012-11-07T19:09:25.163 に答える