Я пытаюсь написать компилятор .NET, используя System.Reflection.Emit, как мне сделать разрешение типов? - PullRequest
3 голосов
/ 09 февраля 2010

У меня есть стратегия для разрешения типов из указанных библиотек. Я застрял при попытке разрешить типы, которые определены в сборке, которая компилируется. Я использую apis System.Reflection.Emit без сторонних библиотек.

Например:

class A {}
class B
{
    public A AnInstanceOfA {get; private set;}
}

Какой лучший способ разрешить ссылку Б на А?

Что по этому поводу:

class A
{
    B AnInstanceOfB {get; set;}
}
class B
{
    A AnInstanceOfA {get; set;}
}

где классы содержат экземпляры друг друга.

Есть ли лучший способ сделать это? Какие шаблоны дизайна я должен реализовать? Я бы предпочел использовать только библиотеки System.Reflection.Emit, но если есть лучший способ сделать это или это невозможно сделать с ними, тогда использование других библиотек является приемлемым.

Спасибо

1 Ответ

3 голосов
/ 10 февраля 2010

Не могли бы вы подробнее рассказать о проблеме, с которой вы столкнулись (возможно, показать код небольшой пример кода, который вам не подходит)? Поскольку TypeBuilder происходит от Type, если вы пытаетесь определить взаимно рекурсивные типы, вы можете передать эти два TypeBuilder везде, где вы хотите сослаться на типы.

EDIT

Нет необходимости "разрешать" типы. У вас есть доступ к TypeBuilder для каждого и вы можете использовать их так же, как если бы они были полностью определенными типами. Вот пример, который генерирует код, который вы запросили в своем обновлении:

private void DefineAutoProp(string name, Type t, TypeBuilder tb)
{
    var fldName = name.Substring(0, 1).ToLower() + name.Substring(1);
    var fld = tb.DefineField(fldName, t, FieldAttributes.Private);
    var prop = tb.DefineProperty(name, PropertyAttributes.None, t, null);
    var getter = tb.DefineMethod("get_" + name, MethodAttributes.Public, t, null);
    var ilg = getter.GetILGenerator();
    ilg.Emit(OpCodes.Ldarg_0);
    ilg.Emit(OpCodes.Ldfld, fld);
    ilg.Emit(OpCodes.Ret);
    var setter = tb.DefineMethod("set_" + name, MethodAttributes.Public, typeof(void), new[] { t });
    ilg = setter.GetILGenerator();
    ilg.Emit(OpCodes.Ldarg_0);
    ilg.Emit(OpCodes.Ldarg_1);
    ilg.Emit(OpCodes.Stfld, fld);
    ilg.Emit(OpCodes.Ret);
    prop.SetGetMethod(getter);
    prop.SetSetMethod(setter);
}

public void DefineTypes()
{
    var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("test"), AssemblyBuilderAccess.Run);
    var mb = ab.DefineDynamicModule("test");
    var A = mb.DefineType("A", TypeAttributes.Public | TypeAttributes.Class);
    var B = mb.DefineType("B", TypeAttributes.Public | TypeAttributes.Class);
    DefineAutoProp("AnInstanceOfA", A, B);
    DefineAutoProp("AnInstanceOfB", B, A);
    A.CreateType();
    B.CreateType();
}
...