“System.TypeLoadException:内部限制:字段太多。”具有大型静态数据结构

时间:2010-10-12 20:33:29

标签: c# .net typeloadexception

我有一个带有静态类的小型C#库,它包含一个非常大但简单的四维字节数组,表示一个多维决策表(总共大约90K字节)。

还有另外一个值得注意的数据结构,一个有助于索引到决策表第一维的字典。

此决策表是一个静态私有数据成员,由数组静态初始值设定项初始化。代码在Visual Studio 2010中使用T4从Excel文档生成。

决策是通过索引到多维数组的静态方法获得的。

当我使用这个库运行一个简单的测试应用程序时,它会弹出一个“System.TypeLoadException:内部限制:太多字段”。例外,在第一次调用静态决策方法时。

Stackoverflow上的one remotely related主题提到带有“太多符号”的库。我可能错了,但我的图书馆似乎确实很少有符号。

这里发生了什么?

代码段:

        private static byte[][][][] decisions = new byte[][][][] {
    new byte[][][] { 
    new byte[][] { 
    new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6}

    },
    new byte[][] { 
    new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},
    new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6},new byte[]{5,6,6}

    },

......等等......

3 个答案:

答案 0 :(得分:4)

  

new byte [] {5,6,6}

这里的问题是初始化器{5,6,6}创建了一个静态字段。你可以用Ildasm.exe看到它。 CLR在一个类中强加了最多65535个字段。您自动生成的代码超出了它。

你将不得不以不同的方式做到这一点。想到了一个文件。

答案 1 :(得分:0)

哇。挺有趣的。我不能评论那个特定的错误(虽然我希望它实际上是太多的中间本地人),但是在某些非常类似的(基于codegen的决策引擎)我通过序列化填充数据(二进制在我的情况,但任何应该工作)。这意味着两步加载(创建obj,从文件加载)但它工作得非常好。

暂且不说: 我的构造函数足以让反射器在乱糟糟的堆中爆炸(非常终端错误),所以我感觉到你的痛苦。

答案 2 :(得分:0)

您可以尝试显式地在静态构造函数中发出代码,并直接在子数组中索引,而不是使用数组初始化器语法。这将阻止静态字段的创建,而是将所有数据设置编码为大量的IL。我不确定在一种方法中IL的数量是否有类似的限制,但我相信你会发现你是否相应地修改了T4。

看起来像是:

static MyClass()
{
    decisions = new byte[N1][][][];
    decisions[0] = new byte[N2][][];
    ....
    decisions[0][0][0][0] = 5;
    decisions[0][0][0][1] = 6;
    decisions[0][0][0][2] = 6;
    ...
}