2009-07-31 11 views
32

En another question pregunté, surgió un comentario que indica que el método de .NET Framework Array.Copy utiliza código no administrado. Fui a cavar con Reflector y encontré la firma uno de los Array.Copy sobrecargas método se define como tan:Externo interno estático C# con atributo InternalCall - ¿interno o externo?

[MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
internal static extern void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length, bool reliable); 

Después de ver esto, estoy un poco confundido. La fuente de mi confusión es el modificador extern que significa (MSDN link):

El modificador externo se utiliza para declarar un método que se implementa externamente.

Sin embargo, la declaración de método también está decorado con un atributo MethodImplOptions.InternalCall, lo que indica (MSDN link):

Especifica una llamada interna. Una llamada interna es una llamada a un método que se implementa dentro del tiempo de ejecución del lenguaje común .

¿Alguien puede explicar esta aparente contradicción aparente?

Respuesta

46

Hubiera comentado en la publicación leppie's, pero se estaba poniendo un poco largo.

Actualmente estoy trabajando en una implementación experimental de CLI. Hay muchos casos en los que un método (o propiedad) expuesto públicamente no se puede implementar sin el conocimiento de cómo se implementa la máquina virtual internamente. Un ejemplo es OffsetToStringData, que requiere el conocimiento de cómo el administrador de memoria asigna cadenas.

En casos como este, donde no hay un código C# para expresar el método, puede tratar cada llamada al método de una manera especial interna para el proceso JIT. Como ejemplo aquí, reemplazando el call código de bytes con un ldc.i4 (carga constante entero) antes de pasarlo al generador de código nativo. La bandera InternalCall significa "El cuerpo de este método es tratado de manera especial por el tiempo de ejecución en sí". Puede haber una implementación real o no, en muchos casos en mi código la llamada es tratada como un intrinsic por el JIT.

Existen otros casos en los que el JIT puede tener información especial disponible que permite la optimización de un método. Un ejemplo son los métodos Math, donde aunque estos can be implemented in C#, que especifican InternalCall para hacerlos efectivamente intrínsecos, tienen importantes beneficios de rendimiento.

En C#, un método debe tener un cuerpo a menos que sea abstract o extern. El extern significa un general "Puede llamar a este método desde el código C#, pero el cuerpo del mismo está realmente definido en otro lugar". Cuando el JIT llega a una llamada a un método extern, busca dónde encontrar el cuerpo y se comporta de diferentes maneras según el resultado.

  • El atributo DllImport indica al JIT que cree un talón de P/Invoke para llamar a una implementación de código nativo.
  • La bandera InternalCall indica al JIT que trate la llamada de forma autodefinida.
  • (hay algunos otros, pero no tengo ejemplos de la parte superior de la cabeza durante su uso.)
15

InternalCall medios provistos por el marco.

extern dice que no está proporcionando el código.

extern se puede utilizar en 2 situaciones generales, como arriba, o con p/invoke.

Con p/invoke, simplemente diga el método donde obtener la implementación.

+0

@leppie - Me gustaría poder marcar las suyas y las respuestas de 280Z28 aceptada ya que' re ambos correctos. Sin embargo, creo que la respuesta de 280Z28 lo deletrea un poco más y me ayudó a entender mejor, sin embargo, muchas gracias por su esfuerzo. – CraigTP

+0

No hay problema, ya tengo suficientes puntos, le daré un poco más también :) – leppie

Cuestiones relacionadas