为什么c#编译器会从此代码创建PrivateImplementationDetails?

And*_*ock 29 c#

我发现了以下代码:

public static class MimeHelper
    {
        public static string GetMimeType(string strFileName)
        {
            string retval;
            switch (System.IO.Path.GetExtension(strFileName).ToLower())
            {
                case ".3dm": retval = "x-world/x-3dmf"; break;
                case ".3dmf": retval = "x-world/x-3dmf"; break;
                case ".a": retval = "application/octet-stream"; break;
                // etc...
                default: retval = "application/octet-stream"; break;
            }
            return retval;
        } 
    }
Run Code Online (Sandbox Code Playgroud)

导致编译器创建这个无命名空的内部类(从Reflector复制):

<PrivateImplementationDetails>{621DEE27-4B15-4773-9203-D6658527CF2B}
    - $$method0x60000b0-1 : Dictionary<String, Int32>
    - Used By: MimeHelper.GetMimeType(String) : String
Run Code Online (Sandbox Code Playgroud)

这是为什么?我如何更改上面的代码,以免发生(只是出于兴趣)

谢谢

安德鲁

tva*_*son 26

它正在创建字典来处理switch语句中各种情况的查找,而不是从中设置多个分支ifs来设置返回值.相信我 - 你不想改变它的做法 - 除非你想让地图明确.

ASIDE:我原先假设字典将每个案例的地图存储到索引中,并将其存储到另一个地图中以获取返回值.根据@Scott(参见注释),它实际上将索引存储到应该为该情况执行的代码的标签.当您考虑将为每种情况执行的代码可能不同并且可能比给定示例中的代码长得多时,这绝对有意义.

编辑:基于您的评论,我想我可能想要将映射存储在外部配置文件中,在启动时读取它们,并构建实际映射 - 从键到值的单级映射或类似的多级别从键到索引,从索引到值.我认为在配置文件中维护这些映射比在每次需要添加或删除特定案例时更新代码更容易.

  • 你是正确的,整数是索引.但是,它们不是返回值索引.相反,它们是标签数组的索引.JIT编译器使用标签数组和从整数返回的int值快速跳转到相应的case标签,而无需进行一堆比较. (2认同)

小智 5

发生的事情是编译器正在创建一个内部类,它在编译时发出。此类称为<PrivateImplementationDetails>{99999999-9999-9999-9999-999999999999},此类的GUID组件在编译时生成,因此每次构建时都会更改。在此类的内部,有一个字典,其中包含不同的case变量,以及一个与每个值相对应的int。然后,它用字典中的查找替换switch语句以获取相应的int,并在int值上进行切换(比做一堆刺比较要有效得多)。