2011-03-17 19 views
27

Sé que los genéricos son compilados por JIT (como todo lo demás), a diferencia de las plantillas que se generan cuando se compila el código.
El hecho es que se pueden crear nuevos tipos genéricos en tiempo de ejecución mediante el uso de la reflexión.
que, por supuesto, puede afectar las restricciones del genérico. Que ya pasó el analizador semántico.¿Cómo se compilan los genéricos mediante el compilador JIT?

¿Alguien puede explicar cómo se maneja esto? Y que pasa exactamente?
(Generación de código y comprobación semántica)

+3

Las restricciones no son solo aplicadas por el compilador, la fluctuación también las verifica. Hay varios aspectos no tan triviales de los genéricos, la forma en que se obtienen los ngen-ed es particularmente abrumador. No les llevó 5 años. –

Respuesta

35

Recomiendo leer Generics in C#, Java, and C++: A Conversation with Anders Hejlsberg.

Qn 1. ¿Cómo se compilan los genéricos mediante el compilador JIT ?

de la entrevista:

Anders Hejlsberg: [...] En el CLR [Common Language Runtime], al compilar la lista, o cualquier otra tipo genérico, que compila abajo a IL [Idioma intermedio] y metadatos al igual que cualquier tipo normal. La IL y metadatos contiene información adicional que sabe que hay un parámetro de tipo , por supuesto, pero en principio, un tipo genérico compila sólo la forma en que lo haría cualquier otro tipo compilación. En tiempo de ejecución, cuando su aplicación hace su primera referencia en la lista, el sistema parece ver si alguien ya ha pedido List<int>. Si no, ingresa en el JIT IL y metadatos para List<T> y el argumento de tipo int. El JITer, en el proceso de JITing the IL, también sustituye el parámetro de tipo.

[...]

Ahora, lo que a continuación hacemos es para todo tipo ejemplificaciones que son de valor tipos, tales como List<int>, List<long>, List<double>, List<float> -nos crear una copia única del ejecutable de código nativo . Entonces, List<int> tiene su propio código. List<long> obtiene su propio código. List<float> tiene su propio código. Para todos los tipos de referencia compartimos el código, porque son representacionalmente idénticos. Solo son punteros.


Qn 2. La cosa es que los nuevos tipos genéricos se pueden crear en tiempo de ejecución mediante reflexión. Lo que por supuesto puede afectar las restricciones del genérico. Que ya pasó el analizador semántico. ¿Alguien puede explicar cómo se maneja esto ?

Esencialmente, IL retiene una vista de alto nivel de los tipos genéricos, que permite que el CLR para comprobar las restricciones de 'construido dinámicamente' tipos genéricos en tiempo de ejecución al igual que el compilador de C# podría hacer por tipos 'estáticamente construidos' en código fuente C# en tiempo de compilación.

Aquí hay otro fragmento (el énfasis es mío):

Anders Hejlsberg: [...] Con una limitación, se puede izar que comprobación dinámica de su código y tienen que ser verificable en tiempo de compilación o tiempo de carga. Cuando diga K debe implementar IComparable, ocurren un par de cosas. En cualquier valor de tipo K, , ahora puede acceder directamente a los métodos de interfaz sin conversión, , ya que semánticamente en el programa se garantiza que implementará esa interfaz. Siempre que intente y cree una instanciación de ese tipo, , el compilador comprobará que cualquier tipo que proporcione como el argumento K implemente IComparable, o bien obtendrá un error de compilación . O si lo está haciendo con reflejo se obtiene una excepción.

Bruce Eckel: Usted dijo el compilador y el tiempo de ejecución.

Anders Hejlsberg: El compilador comprueba , pero que podría también estar haciéndolo en tiempo de ejecución con la reflexión, y entonces el sistema comprueba si se . Como dije antes, cualquier cosa que pueda hacer en tiempo de compilación, también lo puede hacer en tiempo de ejecución con reflejo.

2

Tipos de referencia genéricos todos se convierten en el mismo tipo; los genéricos de tipo de valor se instancian por separado.

Esto se debe a que los tipos de referencia son solo Object referencias (4 u 8 bytes), mientras que los tipos de valores son diferentes y no pueden manejarse con una sola porción de código, debido a diferencias en el diseño de la pila, etc. las copias de un tipo genérico con tipos de valor aumentarán mucho el uso de memoria, mientras que la creación de instancias de copias múltiples con tipos de referencia no lo hará.

+1

No son del mismo tipo. Comparten el mismo código de máquina para funciones miembro (métodos) ... pero cada uno es un tipo distinto con su propia copia de variables de miembros estáticos. –

+0

@BenVoigt: Bien ... gracias por la aclaración. – Mehrdad

Cuestiones relacionadas