El propósito de ese atributo es doble:
- de gestión de llamadas in situ , ya sea para hacer cumplir la inicialización de variables o no
- Marshalling
Si se va a llamar a ese método de C#, o un lenguaje similar con una semántica similar, tal parámetro sería conocido a el compilador no necesita un valor inicial.
En otras palabras, se puede hacer esto:
int a;
CallSomeMethodWithOutParameter(out a);
y el compilador sabe que no hay necesidad de asegurar que a
ya tiene un valor antes de hacer la llamada.
Por otra parte, sin el atributo, se necesitaría la siguiente, de nuevo en C#:
int a = 0; // <-- notice initialization here
CallSomeMethodWithOutParameter(ref a); // <-- and ref here
El otro propósito es para llamadas a métodos que serán movilizados en un contexto de llamada diferente, por ejemplo a través P/Invocar a un dominio de aplicación diferente oa un servicio web para notificar a las rutinas de clasificación que el parámetro en cuestión contendrá un valor cuando el método retorne, pero no es necesario pasar ningún valor al método al llamarlo .
Esto puede marcar la diferencia cuando los parámetros y valores devueltos deben empaquetarse y transportarse a la ubicación remota donde se realiza la llamada real.
En otras palabras, si se va a especificar que en una llamada al método utilizado por P/Invoke, ninguna de clasificación se llevará a cabo del valor del parámetro existente cuando el método se llama, pero cuando el método vuelve su el valor vuelve a su código de llamada.
Tenga en cuenta que esta optimización depende de la rutina de clasificación para usar, o no, estos son los detalles de implementación. El atributo simplemente le dice a la rutina qué parámetros puede hacer con eso, no es una instrucción que siempre se seguirá.
¿No importaría C# solo si compilara el código en cuestión? ¿No es "ref" y "out" idéntico en el sitio de llamada?- no importa :) –En realidad, lo que significa es que si la variable no se escribió antes de llamar a la rutina en cuestión, el compilador insertará código en silencio para inicializar la ubicación de almacenamiento que contiene la variable en lugar de quejarse (no hay garantía de dónde se colocará dicho código, ni hay ninguna garantía de que una variable que abandona y vuelve a entrar en el alcance no continúe usando la misma ubicación de almacenamiento sin reinicialización). El compilador realmente no puede suponer que la variable fue escrita, ya que no puede estar seguro de que la rutina llamada realmente la escriba. – supercat
@supercat: Depende del nivel al que estemos considerando las cosas. El nivel "verificar que tu código fuente es válido" * supone * que la variable fue escrita. El nivel "emitir IL" no lo hace, aunque una implementación diferente dirigida a una plataforma diferente * podría * ser capaz de hacerlo. –