我有以下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
需要使用此关键字来消除歧义。