Reflection.Emit代码调用“base”。而不是“这个”。在布尔域上
我有以下 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)。
我正在使用 Reflector 的 Reflection.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);
I have the following class A.
public class A
{
public string Name { get; set; }
}
I need to emit a dynamic proxy using Reflection.Emit to override 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.
}
}
However, the actual generated code (viewed with Reflector) is:
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);
}
}
..which of course throws a System.FieldAccessException (since no such member exists). The correct is to call this.equalsHasBeenCalled (not base.equalsHasBeenCalled).
I am using the Reflection.Emit add-in for Reflector to generate the code (field1 is the FieldInfo for the "equalsHasBeenCalled" field):
// 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);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为什么不用 C# 编写所需的内容,反编译为 IL,然后看看它是如何设置的?另外,如果您需要在项目中执行更多类似的操作,我建议您查看 Castle DynamicProxy。
Why dont you write what you need in C#, decompile to IL and see how it's set up? Also, if you need to do any more of things like this in your project, I suggest you look into Castle DynamicProxy.
也许 this 关键字会触发 Reflection.Emit 加载项中的错误,使其生成错误的代码。尝试删除它,因为它实际上并没有做任何事情,没有其他
equalsHasBeenCalled
您需要使用 this 关键字来消除歧义。Perhaps the this keyword is triggering a bug in your Reflection.Emit add-in to make it generate the wrong code. Try removing it as it is not really doing anything, there is no other
equalsHasBeenCalled
you need to disambiguate using the this keyword.