我在第6章通过C#第四版阅读CLR:
如果将方法定义为非虚拟方法,则永远不要将来将其更改为虚拟方法。原因是因为某些编译器将通过使用call指令而不是callvirt指令来调用非虚拟方法。如果方法从非虚拟更改为虚拟,并且未重新编译引用代码,则将以非虚拟方式调用虚拟方法,从而导致应用程序产生不可预测的行为。如果引用代码是用C#编写的,那么这不是问题,因为C#通过使用callvirt调用所有实例方法。但是,如果引用代码是使用其他编程语言编写的,则可能会出现问题。
但我不太清楚可能会发生哪种不可预测的行为?您能否举个例子或解释作者指的是哪种意外行为?
调用OpCode的文档表明,以非虚拟方式调用虚拟方法是可以接受的。它将仅基于IL中的已编译类型而不是运行时类型信息来调用该方法。
但是,据我所知,如果您非虚拟地调用虚拟方法,该方法将无法通过验证。这是一个简短的测试程序,在该程序中,我们将动态发出用于调用方法(虚拟或非虚拟),编译并运行它的IL:
using System.Reflection;
using System.Reflection.Emit;
public class Program
{
public static void Main()
{
// Base parameter, Base method info
CreateAndInvokeMethod(false, new Base(), typeof(Base), typeof(Base).GetMethod("Test"));
CreateAndInvokeMethod(true, new Base(), typeof(Base), typeof(Base).GetMethod("Test"));
CreateAndInvokeMethod(false, new C(), typeof(Base), typeof(Base).GetMethod("Test"));
CreateAndInvokeMethod(true, new C(), typeof(Base), typeof(Base).GetMethod("Test"));
Console.WriteLine();
// Base parameter, C method info
CreateAndInvokeMethod(false, new Base(), typeof(Base), typeof(C).GetMethod("Test"));
CreateAndInvokeMethod(true, new Base(), typeof(Base), typeof(C).GetMethod("Test"));
CreateAndInvokeMethod(false, new C(), typeof(Base), typeof(C).GetMethod("Test"));
CreateAndInvokeMethod(true, new C(), typeof(Base), typeof(C).GetMethod("Test"));
Console.WriteLine();
// C parameter, C method info
CreateAndInvokeMethod(false, new C(), typeof(C), typeof(C).GetMethod("Test"));
CreateAndInvokeMethod(true, new C(), typeof(C), typeof(C).GetMethod("Test"));
}
private static void CreateAndInvokeMethod(bool useVirtual, Base instance, Type parameterType, MethodInfo methodInfo)
{
var dynMethod = new DynamicMethod("test", typeof (string),
new Type[] { parameterType });
var gen = dynMethod.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
OpCode code = useVirtual ? OpCodes.Callvirt : OpCodes.Call;
gen.Emit(code, methodInfo);
gen.Emit(OpCodes.Ret);
string res;
try
{
res = (string)dynMethod.Invoke(null, new object[] { instance });
}
catch (TargetInvocationException ex)
{
var e = ex.InnerException;
res = string.Format("{0}: {1}", e.GetType(), e.Message);
}
Console.WriteLine("UseVirtual: {0}, Result: {1}", useVirtual, res);
}
}
public class Base
{
public virtual string Test()
{
return "Base";
}
}
public class C : Base
{
public override string Test()
{
return "C";
}
}
输出:
UseVirtual:否,结果:System.Security.VerificationException:操作可能会使运行时不稳定。
UseVirtual:正确,结果:基本
UseVirtual:False,结果:System.Security.VerificationException:操作可能会使运行时不稳定。
UseVirtual:正确,结果:CUseVirtual:否,结果:System.Security.VerificationException:操作可能会使运行时不稳定。
UseVirtual:true,结果:System.Security.VerificationException:操作可能会使运行时不稳定。
UseVirtual:否,结果:System.Security.VerificationException:操作可能会使运行时不稳定。
UseVirtual:true,结果:System.Security.VerificationException:操作可能会使运行时不稳定。UseVirtual:否,结果:System.Security.VerificationException:操作可能会使运行时不稳定。
UseVirtual:正确,结果:C
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句