我有一个.NET库,我试图更多地了解.NET的内部工作原理。所以我将通过ECMA-335规范并使用CFF Explorer VII。
我的问题是,在TypeSpec表中,Signature是Blob堆的索引,应该是TypeSpec签名,如第23.2.14节所述。这意味着它可以是PTR,FNPTR,ARRAY,SZARRAY,GENERICINSTANCE(ELEMENT_TYPE_为简洁而删除)。
但是,我在这个TypeSpec表中有两个条目,它们似乎没有被元数据中的任何其他表引用,并且类型为VAR 0x13和MVAR 0x1e。
此程序集在VS2010中针对.NET 4编译。
ECMA-335会让我相信这是一个错误,但它是使用MS C#编译器编译的。
有谁知道它们是什么以及它们是什么意思?
更新
经过大量的讨论,这段代码在TypeSpec表中创建了这两个条目。
public class AllOutputTypesClass<T> {
public void GenericMethod<N>(N anItem) {
string s = anItem.ToString();
}
public string GenericMethod<N>(T anItem, N secondItem) {
return anItem.ToString();
}
}
答案 0 :(得分:4)
示例中的两个TypeSpec标记都是从方法实现中的IL引用的,而不是从元数据引用的。例如,您的某个方法的IL如下所示:
.method public hidebysig instance string
GenericMethod<N>(!T anItem,
!!N secondItem) cil managed
{
// Code size 19 (0x13)
.maxstack 1
.locals init (string V_0)
IL_0000: nop
IL_0001: ldarga.s anItem
IL_0003: constrained. !T
IL_0009: callvirt instance string [mscorlib]System.Object::ToString()
IL_000e: stloc.0
IL_000f: br.s IL_0011
IL_0011: ldloc.0
IL_0012: ret
} // end of method AllOutputTypesClass`1::GenericMethod
TypeSpec标记用于表示约束前缀中的“!T”。您将在另一个方法的主体中看到与其他TypeSpec标记类似的引用。
答案 1 :(得分:2)
如果您使用ILDasm,您可以获得方法的详细分类,转到视图 - &gt;元信息 - &gt;选择更多Hex。然后转到视图 - &gt;元信息 - &gt;显示!
以下是第二种方法的细分:
Method #2 (06000002)
-------------------------------------------------------
MethodName: GenericMethod (06000002)
Flags : [Public] [HideBySig] [ReuseSlot] (00000086)
RVA : 0x0000206c
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
generic
Type Arity:1
ReturnType: String
2 Arguments
Argument #1: Var!0
Argument #2: MVar!!0
Signature : 30 01 02 0e 13 00 1e 00
1 Generic Parameters
(0) GenericParamToken : (2a000003) Name : N flags: 00000000 Owner: 06000002
2 Parameters
(1) ParamToken : (08000002) Name : anItem flags: [none] (00000000)
(2) ParamToken : (08000003) Name : secondItem flags: [none] (00000000)
如果再向下滚动,您也会看到TypeSpec表条目。
TypeSpec : MVar!!0
Signature: 1e 00
TypeSpec : Var!0
Signature: 13 00
ILdasm上面显示的是VAR(13 00)是通用的!在类级别传递的T(类型定义中的通用参数),MVAR(1e 00)是在方法级别传递的通用!! N(方法定义中的通用参数。)
但是......你已经知道了很多,Orion有你的答案 - TypeSpec表中的条目正在IL中使用。一个条目用于一种方法,另一个条目用于另一种方法。当您查看方法时,您可以在ILdasm中看到这一点:
.method /*06000001*/ public hidebysig instance void
'GenericMethod'<'N'>(!!'N' 'anItem') cil managed
// SIG: 30 01 01 01 1E 00
{
// Method begins at RVA 0x2050
// Code size 16 (0x10)
.maxstack 1
.locals /*11000001*/ init ([0] string 's')
IL_0000: /* 00 | */ nop
IL_0001: /* 0F | 01 */ ldarga.s 'anItem'
IL_0003: /* FE16 | (1B)000001 */ constrained. !!'N'/*1B000001*/
IL_0009: /* 6F | (0A)000011 */ callvirt instance string ['mscorlib'/*23000001*/]'System'.'Object'/*01000001*/::'ToString'() /* 0A000011 */
IL_000e: /* 0A | */ stloc.0
IL_000f: /* 2A | */ ret
} // end of method 'AllOutputTypesClass`1'::'GenericMethod'
和
.method /*06000002*/ public hidebysig instance string
'GenericMethod'<'N'>(!'T' 'anItem',
!!'N' 'secondItem') cil managed
// SIG: 30 01 02 0E 13 00 1E 00
{
// Method begins at RVA 0x206c
// Code size 19 (0x13)
.maxstack 1
.locals /*11000001*/ init ([0] string 'CS$1$0000')
IL_0000: /* 00 | */ nop
IL_0001: /* 0F | 01 */ ldarga.s 'anItem'
IL_0003: /* FE16 | (1B)000002 */ constrained. !'T'/*1B000002*/
IL_0009: /* 6F | (0A)000011 */ callvirt instance string ['mscorlib'/*23000001*/]'System'.'Object'/*01000001*/::'ToString'() /* 0A000011 */
IL_000e: /* 0A | */ stloc.0
IL_000f: /* 2B | 00 */ br.s IL_0011
IL_0011: /* 06 | */ ldloc.0
IL_0012: /* 2A | */ ret
} // end of method 'AllOutputTypesClass`1'::'GenericMethod'
0x1b表是TypeSpec,因此上述方法中的以下行显示了您想知道的2行的用法:
IL_0003: /* FE16 | (1B)000001 */ constrained. !!'N'/*1B000001*/
和
IL_0003: /* FE16 | (1B)000002 */ constrained. !'T'/*1B000002*/