【问题标题】:"System.TypeLoadException: Internal limitation: too many fields." With Large Static Data Structure“System.TypeLoadException:内部限制:字段太多。”具有大型静态数据结构
【发布时间】:2010-10-12 20:33:29
【问题描述】:

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

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

这个决策表是一个静态私有数据成员,由数组静态初始化器初始化。代码是在带有 T4 的 Visual Studio 2010 中从 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}

    },

...等等...

【问题讨论】:

    标签: c# .net typeloadexception


    【解决方案1】:

    新字节[]{5,6,6}

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

    您将不得不以不同的方式执行此操作。突然想到一个文件。

    【讨论】:

    • 我认为在文件中编码数据是最好的选择。如果你真的想阻止用户修改数据,你可以将文件作为资源嵌入。
    • 我喜欢 Stackoverflow!我的目标是快速查找和模糊(决策数据应该很难逆向工程)。一个资源文件,可能是一个序列化的对象
    • (续)- 是一种方法。考虑到我在这个问题上花费的时间过多,我采用了最初的代码生成方法,并使用了一个简化的数组(请参阅下面的答案)。
    【解决方案2】:

    哇。挺有趣的。我无法评论那个特定的错误(尽管我希望它实际上是太多中间本地人),但在类似的东西(基于代码生成的决策引擎)中,我通过序列化填充了数据(我的情况下,但任何应该工作)。这意味着两步加载(创建 obj,从文件加载)但效果很好。

    顺便说一句: 我的构造函数足以让反射器爆炸成一堆乱七八糟的东西(非常终端错误),所以我感受到了你的痛苦。

    【讨论】:

      【解决方案3】:

      您可以尝试在静态构造函数中显式发出代码并直接在子数组中进行索引,而不是使用数组初始值设定项语法。这将阻止静态字段的创建,而是将所有数据设置编码到大量 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;
          ...
      }
      

      【讨论】:

      • 谢谢,丹。我将您的第一个答案标记为已接受的答案,因为它确定了我的问题的根源!我最终将我的数组简化为一个普通的一维数组,甚至比你建议的还要多。鉴于我采用的代码生成方法,并假设每个维度在代码生成时(确实如此)具有已知大小,IMO 的解决方案是等效的。
      • 刚刚注意到我标记的答案属于汉斯。对不起汉斯,谢谢大家!
      猜你喜欢
      • 2010-09-06
      • 2013-09-09
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-05
      • 1970-01-01
      相关资源
      最近更新 更多