2009-04-08 16 views
25

he descubierto que el siguiente código:¿Por qué el compilador de C# crea un PrivateImplementationDetails a partir de este código?

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

hace que el compilador para crear esta namespaceless, clase interna (copiado del reflector):

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

¿Por qué? ¿Cómo podría cambiar el código anterior para que no suceda (justo fuera de interés)

Gracias

Andrew

+1

como fuera de tema, ¿por qué usa un retval de variable de cadena adicional, si puede devolver el cambio inmediatamente? – abatishchev

+0

porque era un trabajo de copiar y pegar desde algún lugar, sí, pude (y lo haré) cambiarlo para hacerlo –

Respuesta

22

Se trata de crear el diccionario de manejar las operaciones de búsqueda de los diversos casos en la sentencia switch en lugar de hacer varias ramificaciones ifs para establecer el valor de retorno. Confía en mí, no quieres cambiar cómo lo está haciendo, a menos que quieras que el mapa sea explícito.

ASIDE: Originalmente asumí que el diccionario almacenaba un mapa de cada caso en un índice en otro mapa para los valores devueltos. De acuerdo con @Scott (ver comentarios), en realidad almacena un índice en una etiqueta para el código que debe ejecutarse para ese caso. Esto tiene sentido absoluto cuando se considera que el código que se ejecutará para cada caso puede diferir y puede ser mucho más largo que en el ejemplo dado.

EDIT: Creo que podría tener la tentación de almacenar las asignaciones en un archivo de configuración externo, leerlas durante el inicio y construir el mapa real, ya sea un mapa de un solo nivel para valorar o un mapa multinivel similar de clave a índice e índice a valor. Creo que sería más fácil mantener estas asignaciones en un archivo de configuración que actualizar el código cada vez que necesita agregar o eliminar un caso en particular.

+0

Pensé eso también pero cuando compilé el tipo localmente (tanto depuración como versión) no vi ningún compilador cosas generadas –

+0

¿Diferente versión del compilador? Contexto diferente? – tvanfosson

+0

¿O tal vez no incluyó tanto en el código reemplazado por las elipsis y no se inició la necesidad de optimizarlo? – tvanfosson

3

Véase this, por ejemplo.

4

Lo que está sucediendo es que el compilador crea una clase interna que emite en tiempo de compilación. Esta clase se llama <PrivateImplementationDetails>{99999999-9999-9999-9999-999999999999}, el componente GUID de esta clase se genera en tiempo de compilación, por lo que cambia con cada compilación. Internamente en esta clase hay un diccionario que contiene las diferentes variables de caso, y un int correspondiente a cada valor. Luego reemplaza la instrucción switch con una búsqueda en el diccionario para obtener la int correspondiente, y hace un cambio en el valor int (mucho más eficiente que hacer una serie de comparaciones).

Cuestiones relacionadas