2009-04-08 1 views
25

Я обнаружил, что следующий код:Почему компилятор C# создает PrivateImplementationDetails из этого кода?

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; 
     } 
    } 

заставляет компилятор создать этот namespaceless, внутренний класс (скопированный с рефлектором):

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

Почему это? Как бы я изменил код выше, так что не происходит (просто из интереса)

Благодарности

Эндрю

+1

как не по теме, почему вы используете дополнительную переменную строки retval, если вы можете сразу вернуться из коммутатора? – abatishchev

+0

, потому что это было копирование и вставка задания откуда-то, да я мог (и будет) изменить его, чтобы сделать это –

ответ

22

Это создает словарь для обработки Lookups различных случаев в заявлении выключателя вместо того чтобы сделать несколько ветвлений ifs из него, чтобы установить возвращаемое значение. Поверьте мне - вы не хотите изменять, как это делается - если вы не хотите сделать карту явной.

ASIDE: Первоначально предполагалось, что словарь хранит карту из каждого случая в индекс на другую карту для возвращаемых значений. Согласно @Scott (см. Комментарии), он фактически хранит индекс для метки для кода, который должен быть выполнен для этого случая. Это имеет смысл, если учесть, что код, который будет выполняться для каждого случая, может отличаться и может быть намного длиннее, чем в данном примере.

EDIT: Основываясь на ваш комментарий, я думаю, что может возникнуть соблазн хранить отображения во внешнем файле конфигурации, читать их в процессе запуска, и построить реальную карту - либо одну карту уровня с ключом к значению или подобной многоуровневой карте от ключа к индексу и индексу к значению. Я думаю, было бы проще поддерживать эти сопоставления в файле конфигурации, чем обновлять код каждый раз, когда вам нужно было добавлять или удалять конкретный случай.

+0

Я тоже так думал, но когда я скомпилировал тип локально (как отладка, так и выпуск), я не видел никакого компилятора сгенерированный материал. –

+0

Разная версия компилятора? Разный контекст? – tvanfosson

+0

Или, возможно, вы не указали столько же в коде, который был заменен на многоточие, и это не вызвало необходимости его оптимизации? – tvanfosson

4

Что происходит, компилятор создает внутренний класс, который он испускает во время компиляции. Этот класс называется <PrivateImplementationDetails>{99999999-9999-9999-9999-999999999999}, компонент GUID этого класса генерируется во время компиляции, поэтому он изменяется с каждой сборкой. Внутри этого класса есть словарь, который содержит разные переменные case, и int, соответствующее каждому значению. Затем он заменяет оператор switch поиском в словаре, чтобы получить соответствующий int, и делает переключатель на значение int (гораздо более эффективное, чем сравнение с кучей скрингов).

Смежные вопросы