反射.发射代码调用“;底座";而不是“;这个";在布尔字段上

本文关键字:quot 这个 布尔 字段 底座 代码 发射 反射 调用 | 更新日期: 2023-09-27 18:21:55

我有以下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.
    }
}

然而,实际生成的代码(使用反射器查看)是:

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.equalsHasBeenColled)。

我正在使用Reflector.Emit插件来生成代码(field1是"equalsHasBeenCalled"字段的FieldInfo):

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

反射.发射代码调用“;底座";而不是“;这个";在布尔字段上

你为什么不在C#中编写你需要的东西,反编译到IL,看看它是如何设置的?此外,如果您需要在项目中做更多类似的事情,我建议您研究Castle DynamicProxy。

也许this关键字触发了反射中的一个错误。发出外接程序使其生成错误的代码。尝试删除它,因为它并没有真正起到任何作用,并没有其他equalsHasBeenCalled需要使用此关键字来消除歧义。