У меня есть следующий класс 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);