válido specification significado programa msil language español detectó common caracteristicas abreviatura c# .net clr cil

c# - significado - common language specification



¿Qué puede hacer en MSIL que no puede hacer en C#o VB.NET? (20)

Todo el código escrito en lenguajes .NET se compila en MSIL, pero ¿hay tareas / operaciones específicas que solo puede hacer mediante MSIL?

Permítanos también hacer las cosas más fácilmente en MSIL que C #, VB.NET, F #, j # o cualquier otro lenguaje .NET.

Hasta ahora tenemos esto:

  1. Recursividad de la cola
  2. Generic Co / Contravariance
  3. Sobrecargas que difieren solo en los tipos de devolución
  4. Anular modificadores de acceso
  5. Tener una clase que no puede heredar de System.Object
  6. Excepciones filtradas (se puede hacer en vb.net)
  7. Llamar a un método virtual del tipo de clase estático actual.
  8. Obtenga un control sobre la versión en caja de un tipo de valor.
  9. Haz una prueba / falla.
  10. Uso de nombres prohibidos.
  11. Defina sus propios constructores sin parámetros para tipos de valores .
  12. Define eventos con un elemento raise .
  13. Algunas conversiones permitidas por CLR pero no por C #.
  14. Cree un método non main() como .entrypoint .
  15. trabaje directamente con int nativo y unsigned int nativo.
  16. Juega con punteros transitorios
  17. directiva emitbyte en MethodBodyItem
  18. Lanzar y atrapar tipos que no sean System.Exception
  19. Heredar enumeraciones (sin verificar)
  20. Puede tratar una matriz de bytes como una matriz (4x más pequeña) de ints.
  21. Puede tener un campo / método / propiedad / evento todos tienen el mismo nombre (no verificado).
  22. Puede volver a ramificar en un bloque de prueba desde su propio bloque de captura.
  23. Usted tiene acceso al especificador de acceso famandassem (el protected internal es fam o assem)
  24. Acceso directo a la clase <Module> para definir funciones globales, o un inicializador de módulo.

20) Puede tratar una matriz de bytes como una matriz (4x más pequeña) de ints.

Usé esto recientemente para hacer una implementación rápida de XOR, ya que la función CLR xor funciona en ints y necesitaba hacer XOR en una secuencia de bytes.

El código resultante medido es ~ 10x más rápido que el equivalente hecho en C # (haciendo XOR en cada byte).

===

No tengo suficiente credz calle para editar la pregunta y agregar esto a la lista como # 20, si alguien más podría que sería genial ;-)


Algo que usan los ofuscadores: puedes tener un campo / método / propiedad / evento que tengan el mismo nombre.


Aquí hay algo más:

  1. Puede tener métodos de instancia adicionales en delegados.
  2. Los delegados pueden implementar interfaces.
  3. Puede tener miembros estáticos en delegados e interfaces.


Creo que la que siempre deseé (con motivos totalmente equivocados) fue la herencia en Enums. No parece algo difícil de hacer en SMIL (ya que los Enums son solo clases) pero no es algo que la sintaxis de C # quiera que hagas.



En IL, puede lanzar y capturar cualquier tipo, no solo los tipos derivados de System.Exception .


En MSIL, puede tener una clase que no puede heredar de System.Object.

Código de muestra: compilarlo con ilasm.exe ACTUALIZACIÓN: debe usar "/ NOAUTOINHERIT" para evitar que el ensamblador herede automáticamente.

// Metadata version: v2.0.50215 .assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z/V.4.. .ver 2:0:0:0 } .assembly sample { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .hash algorithm 0x00008004 .ver 0:0:0:0 } .module sample.exe // MVID: {A224F460-A049-4A03-9E71-80A36DBBBCD3} .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY // Image base: 0x02F20000 // =============== CLASS MEMBERS DECLARATION =================== .class public auto ansi beforefieldinit Hello { .method public hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 13 (0xd) .maxstack 8 IL_0000: nop IL_0001: ldstr "Hello World!" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: ret } // end of method Hello::Main } // end of class Hello


En un try / catch, puede volver a ingresar al bloque try desde su propio bloque catch. Entonces, puedes hacer esto:

.try { // ... MidTry: // ... leave.s RestOfMethod } catch [mscorlib]System.Exception { leave.s MidTry // branching back into try block! } RestOfMethod: // ...

AFAIK no puedes hacer esto en C # o VB


Es posible combinar los modificadores de acceso internal y protected . En C #, si escribe protected internal , se puede acceder a un miembro desde el ensamblado y desde las clases derivadas. A través de MSIL puede obtener un miembro al que solo se puede acceder desde clases derivadas dentro del ensamblaje. (¡Creo que podría ser bastante útil!)


IL tiene la distinción entre call y callvirt para llamadas a métodos virtuales. Al usar el primero, puede forzar a llamar a un método virtual del tipo de clase estática actual en lugar de la función virtual en el tipo de clase dinámica.

C # no tiene forma de hacer esto:

abstract class Foo { public void F() { Console.WriteLine(ToString()); // Always a virtual call! } public override string ToString() { System.Diagnostics.Debug.Assert(false); } }; sealed class Bar : Foo { public override string ToString() { return "I''m called!"; } }

VB, como IL, puede emitir llamadas no MyClass.Method() utilizando la sintaxis MyClass.Method() . En lo anterior, esto sería MyClass.ToString() .


La herencia de Enum no es realmente posible:

Puedes heredar de una clase Enum. Pero el resultado no se comporta como un Enum en particular. No se comporta como un tipo de valor, sino como una clase ordinaria. Lo de Srange es: IsEnum: True, IsValueType: True, IsClass: False

Pero eso no es particularmente útil (a menos que quiera confundir a una persona o el tiempo de ejecución en sí).


La mayoría de los lenguajes .Net, incluidos C # y VB, no usan la función de recursividad de cola del código MSIL.

La recursividad de cola es una optimización que es común en los lenguajes funcionales. Ocurre cuando un método A finaliza devolviendo el valor del método B de forma tal que la pila del método A puede desasignarse una vez que se realiza la llamada al método B.

El código MSIL admite la repetición de cola explícitamente, y para algunos algoritmos esto podría ser una optimización importante. Pero como C # y VB no generan las instrucciones para hacerlo, deben hacerse manualmente (o usando F # o algún otro idioma).

Aquí hay un ejemplo de cómo la recursividad de cola puede implementarse manualmente en C #:

private static int RecursiveMethod(int myParameter) { // Body of recursive method if (BaseCase(details)) return result; // ... return RecursiveMethod(modifiedParameter); } // Is transformed into: private static int RecursiveMethod(int myParameter) { while (true) { // Body of recursive method if (BaseCase(details)) return result; // ... myParameter = modifiedParameter; } }

Es una práctica común eliminar la recursividad moviendo los datos locales de la pila de hardware a una estructura de datos de pila asignada en el montón. En la eliminación de recurrencia de la cola, como se muestra arriba, la pila se elimina por completo, lo cual es una optimización bastante buena. Además, el valor de retorno no tiene que recorrer una larga cadena de llamadas, pero se devuelve directamente.

Pero, de todos modos, CIL proporciona esta característica como parte del lenguaje, pero con C # o VB debe implementarse manualmente. (El jitter también es libre de hacer esta optimización por sí mismo, pero ese es otro problema).


MSIL permite sobrecargas que difieren solo en los tipos de devolución debido a

call void [mscorlib]System.Console::Write(string)

o

callvirt int32 ...


Ooh, no vi esto en ese momento. (Si agrega la etiqueta jon-skeet es más probable, pero no la reviso con tanta frecuencia).

Parece que ya tienes bastante buenas respuestas. En adición:

  • No puede obtener un control sobre la versión en caja de un tipo de valor en C #. Puedes en C ++ / CLI
  • No puede hacer una prueba / falla en C # ("falla" es como "atrapar todo y volver a lanzar al final del bloque" o "finalmente, pero solo en caso de falla")
  • Hay muchos nombres que están prohibidos por C # pero legal IL
  • IL le permite definir sus propios constructores sin parámetros para los tipos de valores .
  • No puede definir eventos con un elemento "subir" en C #. (En VB debe hacerlo para eventos personalizados, pero los eventos "predeterminados" no incluyen uno).
  • Algunas conversiones están permitidas por el CLR pero no por C #. Si vas a través de un object en C #, a veces funcionará. Vea una pregunta de uint [] / int [] SO para un ejemplo.

Añadiré a esto si pienso en otra cosa ...



Puede hackear el método para anular la co / contravariancia, que C # no permite (¡esto NO es lo mismo que la varianza genérica!). Tengo más información sobre cómo implementar esto here , y las partes 1 y 2


También puede definir métodos de nivel de módulo (también conocido como global) en IL, y C #, por el contrario, solo le permite definir métodos siempre que estén adjuntos a al menos un tipo.


También puede derivar una clase del delegado System.Multicast en IL, pero no puede hacer esto en C #:

// La siguiente definición de clase es ilegal:

clase pública YourCustomDelegate: MulticastDelegate {}


Native types
Puede trabajar directamente con int nativo y sin int nativo (en c # solo puede trabajar en un IntPtr que no es el mismo.

Transient Pointers
Puede jugar con punteros transitorios, que son punteros a tipos administrados, pero se garantiza que no se moverán en la memoria ya que no están en el montón administrado. No estoy del todo seguro de cómo podría usar esto sin interferir con el código no administrado, pero no está expuesto a otros idiomas directamente solo a través de cosas como stackalloc.

<Module>
puedes jugar con la clase si lo deseas (puedes hacerlo por reflexión sin necesitar IL)

.emitbyte

15.4.1.1 La directiva .emitbyte MethodBodyItem :: = ... | .emitbyte Int32 Esta directiva hace que un valor sin signo de 8 bits se emita directamente en la secuencia CIL del método, en el punto donde aparece la directiva. [Nota: La directiva .emitbyte se usa para generar pruebas. No es necesario para generar programas regulares. nota final]

.entrypoint
Tiene un poco más de flexibilidad en esto, puede aplicarlo a métodos que no se llaman Main por ejemplo.

lea las spec . Estoy seguro de que encontrará algunas más.