Код Reflection.Emit называет «базой».вместо этого."на булевом поле - PullRequest
1 голос
/ 31 января 2012

У меня есть следующий класс A.

public class A
{
    public string Name { get; set; }
}

Мне нужно создать динамический прокси-сервер, используя Reflection.Emit для переопределения Equals.

// This class must be generated by Reflection.Emit.
public class AProxy : A
{
    private bool equalsHasBeenCalled;

    public override bool Equals(object obj)
    {
        if (this.equalsHasBeenCalled)
        {
            return base.Equals(obj);
        }

        this.equalsHasBeenCalled = true;

        return CaseInsensitiveComparer.Equals(this, obj); // Demo.
    }
}

Однако, фактический сгенерированный код (просматривается с помощью Reflector):

public class AProxy : A
{
    private bool equalsHasBeenCalled;

    public override bool Equals(object obj)
    {
        if (base.equalsHasBeenCalled)
        {
            return base.Equals(obj);
        }

        base.equalsHasBeenCalled = true;

        return CaseInsensitiveComparer.Equals(this, obj);
    }
}

.., что, конечно, вызывает исключение System.FieldAccessException (поскольку такого члена не существует).Правильным является вызов this.equalsHasBeenCalled (не base.equalsHasBeenCalled).

Я использую надстройку Reflection.Emit для Reflector для генерации кода (field1 - это FieldInfo дляполе "equalsHasBeenCalled"):

        // Writing body
        gen.Emit(OpCodes.Nop);

        // I suspect it has to be around here.
        gen.Emit(OpCodes.Ldarg_0);
        gen.Emit(OpCodes.Ldfld, field1);
        gen.Emit(OpCodes.Ldc_I4_0);

        gen.Emit(OpCodes.Ceq);
        gen.Emit(OpCodes.Stloc_1);
        gen.Emit(OpCodes.Ldloc_1);
        gen.Emit(OpCodes.Brtrue_S, label25);
        gen.Emit(OpCodes.Nop);
        gen.Emit(OpCodes.Ldarg_0);
        gen.Emit(OpCodes.Ldarg_1);
        gen.Emit(OpCodes.Call, method2);
        gen.Emit(OpCodes.Stloc_0);
        gen.Emit(OpCodes.Br_S, label42);
        gen.MarkLabel(label25);

        // ..and probably here also?
        gen.Emit(OpCodes.Ldarg_0);
        gen.Emit(OpCodes.Ldc_I4_1);
        gen.Emit(OpCodes.Stfld, field1);

        gen.Emit(OpCodes.Ldarg_0);
        gen.Emit(OpCodes.Ldarg_1);
        gen.Emit(OpCodes.Call, method3);
        gen.Emit(OpCodes.Stloc_0);
        gen.Emit(OpCodes.Br_S, label42);
        gen.MarkLabel(label42);
        gen.Emit(OpCodes.Ldloc_0);
        gen.Emit(OpCodes.Ret);

Ответы [ 2 ]

3 голосов
/ 31 января 2012

Почему бы вам не написать то, что вам нужно в C #, декомпилировать в IL и посмотреть, как он настроен? Также, если вам нужно сделать что-то подобное в вашем проекте, я предлагаю вам взглянуть на Castle DynamicProxy.

0 голосов
/ 31 января 2012

Возможно, это ключевое слово вызывает ошибку в вашей надстройке Reflection.Emit, из-за которой он генерирует неправильный код. Попробуйте удалить его, поскольку на самом деле он ничего не делает, другого equalsHasBeenCalled вам не нужно устранять, используя ключевое слово this.

...