generate - params comments c#
Fuera de parĂ¡metros y excepciones. (5)
Bastante, ese es un aspecto de lo out
significa out
; En primer lugar, tenga en cuenta que el out
no existe realmente, solo necesitamos considerar ref
( out
es simplemente ref
con algunos ajustes de "asignación definida" en el compilador). ref
significa "pasar la dirección de esto": si cambiamos el valor a través de la dirección, entonces eso se muestra de inmediato , es, después de todo, la actualización de la memoria en la pila de Main
. No puede abstraer esto (retrasar la escritura) porque el valor podría ser, por ejemplo, una estructura sobredimensionada que usa ref
Específicamente con el propósito de evitar copiarlo en la pila (un enfoque utilizado ampliamente en XNA, etc.).
Digamos que tengo el siguiente código:
static void Fjuk(out string str)
{
str = "fjuk!";
throw new Exception();
}
static void Main(string[] args)
{
string s = null;
try
{
Fjuk(out s);
}
catch (Exception)
{
Console.WriteLine(s ?? "");
}
}
Cuando lo probé, s
ha sido inicializado a "fjuk!" cuando se usa en el bloque catch
.
¿Esto está garantizado por la especificación o depende de la implementación? (He buscado en la especificación C # 3 pero no pude encontrarlo)
De la sección Especificación de lenguaje C # 5.1.6 Parámetros de salida
Tras la finalización normal de una invocación de miembro o delegado de función, cada variable que se pasó como parámetro de salida se considera asignada en esa ruta de ejecución.
En otras palabras
-
out
parámetros deout
siempre se asignan. - Se sobrescribe cualquier valor anterior.
- pero si la función lanza una excepción, el compilador asume que no están asignados.
En la práctica
- Nunca debes preocuparte por esto.
- Si intenta usar una variable no asignada, el compilador generará un error.
- Por lo tanto, los parámetros en C # son completamente seguros : si se compilan, funcionan.
Está garantizado desde la perspectiva de Fjuk
pero no de Main
.
En Fjuk
la excepción se Fjuk
después de que se establece el parámetro. Si bien el compilador, el jitter y la CPU pueden reordenar, no se reordenarán de manera tal que el orden observado por un solo hilo cambie. Dado que un solo hilo podría "notar" si el parámetro no se configuró antes de que se lanzara la excepción, se garantiza que el parámetro se establezca.
Sin embargo, en Main
, no tenemos conocimiento de los detalles de la Fjuk
de Fjuk
, por lo que cuando el compilador analiza Main
, no puede depender de eso. Por lo tanto, en la variación donde no asignamos un valor a s
antes de la llamada:
static void Main()
{
string s;
try
{
Fjuk(out s);
Console.WriteLine(s ?? "");//fine
}
catch (Exception)
{
Console.WriteLine(s ?? "");//compiler error
}
Console.WriteLine(s ?? "");//compiler error
}
El primer intento de usar s
inmediatamente después de la llamada a Fjuk
está bien, porque solo se puede llegar si Fjuk
tuvo éxito, y si Fjuk
tuvo éxito, entonces se debe asignar s. Sin embargo, en el segundo y tercer caso, es posible llegar a esas líneas sin que Fjuk
éxito, y como no se puede saber mediante el análisis de Main
si se puede lanzar una excepción antes de que se establezca s
deben prohibir los usos de s
.
Si el método lanza una excepción, no se garantiza que el parámetro de salida se establezca. Si el método sale sin una excepción, se garantiza que el parámetro de salida se establecerá.
En su caso, el método siempre establecerá el parámetro de salida, pero el compilador no analiza el código del método de esa manera. Si el método sale con una excepción, el parámetro de salida todavía no se considera definitivamente establecido.
Su código en el controlador de excepciones no se basa en la variable establecida por la llamada al método, ya que está configurando la variable cuando se crea. Si no configura la variable cuando se crea, el controlador de excepciones no puede usarla, porque no se garantiza que se establezca:
string s;
try {
Fjuk(out s);
Console.WriteLine(s); // here the variable is guaranteed to be set
} catch (Exception) {
Console.WriteLine(s); // here it''s not, so this won''t compile
}
Está "garantizado" porque out
parámetro cambia el valor con la memory address
de memory address
del parámetro.
La palabra clave out hace que los argumentos se pasen por referencia. Esto es similar a la palabra clave ref, excepto que ref requiere que la variable se inicialice antes de pasar.
de MSDN