ECMA 公共语言基础设施文档对 CIL“isinst class”指令有这样的描述:
正确的 CIL 确保 class 是指示类的有效 typeref 或 typedef 或 typespec 标记,并且 obj 始终为 null 或对象引用。
这意味着不允许使用值类型,对吧?但 mscorlib.dll 包含一个方法 System.RuntimeTypeHandle::Equals(object obj) ,其指令如下:
IL_0001:正在安装 System.RuntimeTypeHandle
而 System.RuntimeTypeHandle 是一个值类型。有人可以把我放在这里吗?
看看
RuntimeTypeHandle
的声明:
.class public sequential ansi serializable sealed beforefieldinit RuntimeTypeHandle
extends System.ValueType
implements System.Runtime.Serialization.ISerializable
虽然
RuntimeTypeHandle
被声明为结构体,但它在 CIL 中的表示是某种特殊的类。换句话说,您可以将结构想象为继承自 System.ValueType
且其属性遵循严格顺序的特殊类。
考虑到这一点,
isinst
可以用RuntimeTypeHandle
来调用。对于我的解释,isinst
根本不限于引用类型,只要有一个代表该类型的类即可。
假设我们用 C# 编写:
var i = 4;
var b = i is Int32;
我们收到编译器警告
警告:给定的表达式始终是提供的('int')类型。
会发生什么?我们将
4
分配给 i
。 i
变成了int
。在下一行中,i
被自动装箱到其相应的ReferenceType
(类),以便警告显而易见。我们甚至可以写
var b = i is int;
我希望这有助于澄清这个主题。
这意味着不允许使用值类型,对吧?
不,但他们的措辞令人困惑。
class
这里是 isinst
接受的 second参数的名称。它是一个代表接口、类或结构(基本上是任何
Type
)的令牌(可以认为是与类型相关的元数据表之一中的行的索引)。
有点隐藏的是从堆栈传递的第一个参数 - 对象引用。
如果
isinst
是一个 C# 方法,它将是这样的:
object IsInst (object reference, Type type){
if(reference.GetType().IsAssignableTo(type)){
return reference;
}
return null;
}
在
RuntimeTypeHandle.Equals(object obj)
的示例中,您没有包含将对象参数传递给 isinst
的第一行:
IL_0000: ldarg.1 // this is object obj
IL_0001: isinst System.RuntimeTypeHandle
值类型的唯一问题是,从“假”的签名
IsInst
你会认识到我们需要box
我们的值类型实例才能传递它。
例如,这个通用方法保证有一个结构
value
:
bool IsInt<T>(T value)
where T : struct {
if (value is int) {
return true;
}
return false;
}
调用前会有装箱码
isinst
:
IL_0000: ldarg.1
IL_0001: box !!T
IL_0006: isinst [System.Runtime]System.Int32