我正在编写一个输出.NET程序集的编译器(使用Mono.Cecil,虽然我不相信Cecil与此问题相关)。其中一个编译器功能要求类具有编译器生成的嵌套类和一些支持方法;外部类有一个静态字段,因此每个类实际上都有一个引用嵌套类对象的单例。要初始化它,任何这样的类都有一个类构造函数来创建嵌套类的实例并将其存储在字段中。
问题:当我的外部类是泛型类时,我也使嵌套类通用(因为它需要创建外部类的对象)。生成的IL通过peverify正常,看起来很好,但是创建嵌套类实例的类构造函数在运行时抛出OutOfMemoryException。
我用ildasm拆卸了组件,将其缩小到最小的再现(不幸的是仍然是~180行的IL),并且验证用ilasm编译IL会产生仍然存在问题的exe。
使用Visual Studio或MDbg进行调试还没有启发我 - 我只是得到OutOfMemoryException而没有指示为什么。我愿意相信我的IL在某种程度上是无效的,但是peverify并不表示存在问题。任何人都可以提出问题所在吗?
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern System
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly Repro1
{
.ver 0:0:0:0
}
.module Repro1
// MVID: {7DA983B6-F5EA-4ACB-8443-C29F25ADDCD4}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x016E0000
.class public abstract auto ansi sealed Repro1
extends [mscorlib]System.Object
{
.method assembly static void '<NemeaProgram>'() cil managed
{
.entrypoint
// Code size 6 (0x6)
.maxstack 0
IL_0000: call void Rep2::Go()
IL_0005: ret
} // end of method Repro1::'<NemeaProgram>'
} // end of class Repro1
.class public abstract auto ansi sealed Rep1
extends [mscorlib]System.Object
{
.class auto ansi nested public TRep
extends [mscorlib]System.Object
{
.class auto ansi nested public '__%NemeaVType'
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method '__%NemeaVType'::.ctor
.method public newslot virtual instance class Rep1/TRep
Create(string Foo) cil managed
{
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg Foo
IL_0004: newobj instance void Rep1/TRep::.ctor(string)
IL_0009: ret
} // end of method '__%NemeaVType'::Create
} // end of class '__%NemeaVType'
.field famorassem string FData
.field public static class Rep1/TRep/'__%NemeaVType' '__%NemeaVTypeI'
.method public hidebysig specialname rtspecialname
instance void .ctor(string Foo) cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldarg Foo
IL_000b: stfld string Rep1/TRep::FData
IL_0010: ret
} // end of method TRep::.ctor
.method privatescope specialname rtspecialname static
void '.cctor$PST0600004C'() cil managed
{
// Code size 11 (0xb)
.maxstack 8
IL_0000: newobj instance void Rep1/TRep/'__%NemeaVType'::.ctor()
IL_0005: stsfld class Rep1/TRep/'__%NemeaVType' Rep1/TRep::'__%NemeaVTypeI'
IL_000a: ret
} // end of method TRep::.cctor
} // end of class TRep
.class auto ansi nested public TItem
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method TItem::.ctor
} // end of class TItem
} // end of class Rep1
.class public abstract auto ansi sealed Rep2
extends [mscorlib]System.Object
{
.class auto ansi nested public TRep<(Rep1/TItem) T>
extends Rep1/TRep
{
.class auto ansi nested public '__%NemeaVType'<(Rep1/TItem) T_vt>
extends Rep1/TRep/'__%NemeaVType'
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void Rep1/TRep/'__%NemeaVType'::.ctor()
IL_0006: ret
} // end of method '__%NemeaVType'::.ctor
.method public virtual instance class Rep1/TRep
Create(string Foo) cil managed
{
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg Foo
IL_0004: newobj instance void class Rep2/TRep<!T_vt>::.ctor(string)
IL_0009: ret
} // end of method '__%NemeaVType'::Create
} // end of class '__%NemeaVType'
.field public static class Rep2/TRep/'__%NemeaVType'<!T> '__%NemeaVTypeI'
.method public hidebysig specialname rtspecialname
instance void .ctor(string Foo) cil managed
{
// Code size 22 (0x16)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg Foo
IL_0005: call instance void Rep1/TRep::.ctor(string)
IL_0015: ret
} // end of method TRep::.ctor
.method privatescope specialname rtspecialname static
void '.cctor$PST06000055'() cil managed
{
// Code size 11 (0xb)
.maxstack 8
IL_0000: newobj instance void class Rep2/TRep/'__%NemeaVType'<!T>::.ctor()
IL_0005: stsfld class Rep2/TRep/'__%NemeaVType'<!T> Rep2/TRep::'__%NemeaVTypeI'
IL_000a: ret
} // end of method TRep::.cctor
} // end of class TRep
.method public static void Go() cil managed
{
// Code size 29 (0x1d)
.maxstack 1
.locals init ([0] class Rep1/TRep R)
IL_0000: ldstr "Oi"
IL_0005: newobj instance void class Rep2/TRep<class Rep1/TItem>::.ctor(string)
IL_000a: stloc R
IL_001c: ret
} // end of method Rep2::Go
} // end of class Rep2
答案 0 :(得分:2)
事实证明问题与泛型声明没有任何关系 - 嵌套类的声明很好。泛型参数的名称与外部类的泛型参数不匹配,但这只是C#编译器(可理解地)在将泛型参数传播到嵌套类时遵循的约定。
问题只是
IL_0005: stsfld class Rep2/TRep/'__%NemeaVType'<!T> Rep2/TRep::'__%NemeaVTypeI'
行 - 它无效,因为它试图访问Rep2 / TRep类上的字段,这是通用的,而不提供任何类型参数。将此更改为
IL_0005: stsfld class Rep2/TRep/'__%NemeaVType'<!0> Rep2/TRep<!T>::'__%NemeaVTypeI'
解决了所有问题。
我仍然认为peverify 可以突出显示这一点,因为它不是真的有效 - 它不可能正确执行,因为它不是有效的字段引用。在执行代码时得到OutOfMemoryException而不是任何有更多细节的东西也有点烦人。