- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个递归函数 emit : Map<string,LocalBuilder> -> exp -> unit
哪里il : ILGenerator
对函数来说是全局的,并且 exp
是一个判别联合,表示带有大小写 InstanceCall of exp * MethodInfo * exp list * Type
的类型检查的解析语言和 Type
是 exp
上的属性(property)表示表达式的类型。
在下面的片段中,我试图为一个实例调用发出 IL 操作码,其中 instance.Type
可能是也可能不是 ValueType
.所以我知道我可以使用 OpCodes.Constrained
灵活高效地对引用、值和枚举类型进行虚拟调用。我是 Reflection.Emit 和机器语言的新手,所以了解 OpCodes.Constrained
的链接文档对我来说不强。
这是我的尝试,但结果是 VerificationException
, "操作可能会破坏运行时的稳定性。":
let rec emit lenv ast =
match ast with
...
| InstanceCall(instance,methodInfo,args,_) ->
instance::args |> List.iter (emit lenv)
il.Emit(OpCodes.Constrained, instance.Type)
il.Emit(OpCodes.Callvirt, methodInfo)
...
OpCodes.Constrained
(
instance.Type
是 ValueType,但
methodInfo.DeclaringType
是引用类型)。
let rec emit lenv ast =
match ast with
| Int32(x,_) ->
il.Emit(OpCodes.Ldc_I4, x)
...
| InstanceCall(instance,methodInfo,args,_) ->
emit lenv instance
//if value type, pop, put in field, then load the field address
if instance.Type.IsValueType then
let loc = il.DeclareLocal(instance.Type)
il.Emit(OpCodes.Stloc, loc)
il.Emit(OpCodes.Ldloca, loc)
for arg in args do emit lenv arg
if instance.Type.IsValueType then
il.Emit(OpCodes.Call, methodInfo)
else
il.Emit(OpCodes.Callvirt, methodInfo)
...
最佳答案
基本上我同意 Tomas:如果您在编译时知道确切的类型,那么您可以自己发出正确的调用指令。约束前缀通常用于泛型代码
但文档也说:
The constrained opcode allows IL compilers to make a call to a virtual function in a uniform way independent of whether ptr is a value type or a reference type. Although it is intended for the case where thisType is a generic type variable, the constrained prefix also works for nongeneric types and can reduce the complexity of generating virtual calls in languages that hide the distinction between value types and reference types. ...
Using the constrained prefix also avoids potential versioning problems with value types. If the constrained prefix is not used, different IL must be emitted depending on whether or not a value type overrides a method of System.Object. For example, if a value type V overrides the Object.ToString() method, a call V.ToString() instruction is emitted; if it does not, a box instruction and a callvirt Object.ToString() instruction are emitted. A versioning problem can arise in the former case if the override is later removed, and in the latter case if an override is later added.
using System;
using System.Reflection;
using System.Reflection.Emit;
public struct EvilMutableStruct
{
int i;
public override string ToString()
{
i++;
return i.ToString();
}
}
class Program
{
public static void Main()
{
var intToString = Make<int>();
var stringToString = Make<string>();
var structToString = Make<EvilMutableStruct>();
Console.WriteLine(intToString(5));
Console.WriteLine(stringToString("!!!"));
Console.WriteLine(structToString (new EvilMutableStruct()));
}
static MethodInfo ToStringMethod = new Func<string>(new object().ToString).Method;
static MethodInfo ConcatMethod = new Func<string, string, string>(String.Concat).Method;
// x => x.ToString() + x.ToString()
private static Func<T, string> Make<T>()
{
var dynamicMethod = new DynamicMethod("ToString", typeof(string), new[] {typeof(T)});
var il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarga_S, 0);
il.Emit(OpCodes.Constrained, typeof(T));
il.Emit(OpCodes.Callvirt, ToStringMethod);
il.Emit(OpCodes.Ldarga_S, 0);
il.Emit(OpCodes.Constrained, typeof(T));
il.Emit(OpCodes.Callvirt, ToStringMethod);
il.Emit(OpCodes.Call, ConcatMethod);
il.Emit(OpCodes.Ret);
return (Func<T, string>)dynamicMethod.CreateDelegate(typeof(Func<T, string>));
}
}
55
!!!!!!
12
关于.net - 鉴于我手头有所需的 MethodInfo 和实例类型,如何使用 OpCodes.Callvirt 发出 OpCodes.Constrained,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6884149/
我是一名优秀的程序员,十分优秀!