Estaba leyendo sobre las nuevas características de las variables de salida en C # 7 aquí . Tengo dos preguntas:
Dice
También permitimos "descartes" como parámetros de salida, en forma de a
_, para permitirle ignorar los parámetros que no le interesan:p.GetCoordinates(out var x, out _); // I only care about xP: Supongo que esto es solo una información y no una característica nueva de C # 7 porque también podemos hacerlo en versiones anteriores a C # 7.0:
var _; if (Int.TryParse(str, out _)) ...o me estoy perdiendo algo aquí?
Mi código da un error cuando hago lo mencionado en el mismo blog:
~Person() => names.TryRemove(id, out *);*no es un identificador válido. ¿Un descuido de Mads Torgersen, supongo?

out __no es una variable, no la declaras y no puedes usarla por su nombre. Enint _eso hay una variable.out _, sinvar. Devarhecho, es lo mismo que antes.Console.WriteLine(_), esto no compilará alegando que no existe tal variable. Bastante raro. Aún más: si hace algo como_ = SomeMethodCall(), esto será reemplazado por soloSomeMethodCall()en código compilado. Entonces, después de todo, todavía no puedes usar esa variable en ningún sentido significativo.Respuestas:
Los descartes , en C # 7, se pueden usar siempre que se declare una variable, para, como sugiere el nombre, descartar el resultado. Entonces, un descarte se puede usar sin variables:
p.GetCoordinates(out var x, out _);y se puede usar para descartar el resultado de una expresión:
_ = 42;En el ejemplo,
p.GetCoordinates(out var x, out _); _ = 42;No se
_está introduciendo ninguna variable`` . Solo hay dos casos en los que se utiliza un descarte.Sin embargo, si
_existe un identificador en el alcance, los descartes no se pueden utilizar:var _ = 42; _ = "hello"; // error - a string cannot explicitly convert from string to intLa excepción a esto es cuando
_se utiliza una variable como variable de salida. En este caso, el compilador ignora el tipo ovary lo trata como un descarte:if (p.GetCoordinates(out double x, out double _)) { _ = "hello"; // works fine. Console.WriteLine(_); // error: _ doesn't exist in this context. }Tenga en cuenta que esto solo ocurre si, en este caso, se usa
out var _oout double _. Solo useout _y luego se trata como una referencia a una variable existente_, si está dentro del alcance, por ejemplo:string _; int.TryParse("1", out _); // complains _ is of the wrong typeFinalmente, la
*notación se propuso al principio de las discusiones sobre los descartes, pero se abandonó_debido a que esta última es una notación más utilizada en otros idiomas .fuente
_debido a que este último es un ...'_ = 42"descartar [s] el resultado de la expresión" es engañoso, porque en_ = 42sí mismo es una expresión con el valor42, por lo que no hay un descarte real. Todavía hay una diferencia porque_ = 42;también es una declaración, mientras42;que no lo es, lo que importa en algunos contextos._ = 42no muestra cuál es el punto de este descarte, es decir, cuando necesitaría "no almacenar" una expresión, pero evaluarla de todos modos, ya que generalmente puede evaluar un (no trivial , útil) expresión muy bien sin almacenarla. Yo mismo no puedo pensar inmediatamente en un ejemplo útil (y no sé si hay uno, o si esto es solo el resultado de la coherencia en la gramática).Otro ejemplo del operador de descarte
_en C # 7 es hacer coincidir el patrón con una variable de tipoobjecten unaswitchdeclaración, que se agregó recientemente en C # 7:Código:
static void Main(string[] args) { object x = 6.4; switch (x) { case string _: Console.WriteLine("it is string"); break; case double _: Console.WriteLine("it is double"); break; case int _: Console.WriteLine("it is int"); break; default: Console.WriteLine("it is Unknown type"); break; } // end of main method }Este código coincidirá con el tipo y descartará la variable pasada al
case ... _.fuente
Para mas curiosos
Considere el siguiente fragmento
static void Main(string[] args) { //.... int a; int b; Test(out a, out b); Test(out _, out _); //.... } private static void Test(out int a, out int b) { //... }Esto es lo que está pasando:
... 13: int a; 14: int b; 15: 16: Test(out a, out b); 02340473 lea ecx,[ebp-40h] 02340476 lea edx,[ebp-44h] 02340479 call 02340040 0234047E nop 17: Test(out _, out _); 0234047F lea ecx,[ebp-48h] 02340482 lea edx,[ebp-4Ch] 02340485 call 02340040 0234048A nop ...Como puede ver detrás de escena, las dos llamadas hacen lo mismo.
Como señaló @ Servé Laurijssen, lo bueno es que no tiene que declarar previamente las variables, lo cual es útil si no está interesado en algunos valores.
fuente
Respecto a la primera pregunta
La novedad es que ya no tienes que declarar
_dentro o fuera de la expresión y solo puedes escribirint.TryParse(s, out _);Intente hacer este trazador de líneas previo a C # 7:
private void btnDialogOk_Click_1(object sender, RoutedEventArgs e) { DialogResult = int.TryParse(Answer, out _); }fuente
SomeMethod(out _, out _, out three)tiene 3 parámetros de salida, pero estoy desechando los dos primeros sin tener que crear variables como,unused1, unused2etc.if (SomeMethod(out _, out _, out _)) _ = 5;¿A qué_se refiere?_variable en absoluto, incluso si usaraout var _. Parece que el guión bajo tiene mayúsculas especiales para descartar el resultado.En C # 7.0 (Visual Studio 2017 alrededor de marzo de 2017), los descartes se admiten en las asignaciones en los siguientes contextos:
Otras notas útiles
Ejemplo simple: aquí no queremos usar el primer y segundo parámetro y solo necesitamos el tercer parámetro
Ejemplo avanzado en caso de interruptor que utilizó también la coincidencia de patrones de caso de interruptor moderno ( fuente )
switch (exception) { case ExceptionCustom exceptionCustom: //do something unique //... break; case OperationCanceledException _: //do something else here and we can also cast it //... break; default: logger?.Error(exception.Message, exception); //.. break;}
fuente
var _; if (Int.TryParse(str, out _))Eso no es lo mismo.
Tu código está realizando una asignación.
En C # 7.0 _ no es una variable, le dice al compilador que descarte el valor
(a menos que haya declarado _ como una variable ... si lo hace, la variable se usa en lugar del símbolo de descarte)
Ejemplo: puede usar _ como una picadura y un int en la misma línea de código :
string a; int b; Test(out a, out b); Test(out _, out _); //... void Test(out string a, out int b) { //... }fuente