I was reading about new out variable features in C#7 here. I have two questions:
It says
We allow \"discards\" as out parameters as w
Consider the following snippet
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)
{
//...
}
This is what's happening:
...
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
...
As you can see behind the scene the two calls are making the same thing.
As @Servé Laurijssen pointed out the cool thing is that you don't have to pre-declare variables which is handy if you are not interested in some values.
In C# 7.0 (Visual Studio 2017 around March 2017), discards are supported in assignments in the following contexts:
Other useful notes
Simple example : here we do not want to use the 1st and 2nd params and only need the 3rd param
(_, _, area) = city.GetCityInformation(cityName);
Advanced example in switch case which used also modern switch case pattern matching (source)
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;
}
Regarding the first question
I guess this is just an info and not a new feature of C#7 because we can do so in pre C#7.0 too.
var _; if (Int.TryParse(str, out _)) // ...
The novelty is that you dont have to declare _
anymore inside or outside the expression and you can just type
int.TryParse(s, out _);
Try to do this one liner pre C#7:
private void btnDialogOk_Click_1(object sender, RoutedEventArgs e)
{
DialogResult = int.TryParse(Answer, out _);
}
Discards, in C#7 can be used wherever a variable is declared, to - as the name suggests - discard the result. So a discard can be used with out variables:
p.GetCoordinates(out var x, out _);
and it can be used to discard an expression result:
_ = 42;
In the example,
p.GetCoordinates(out var x, out _);
_ = 42;
There is no variable, _
, being introduced. There are just two cases of a discard being used.
If however, an identifier _
exists in the scope, then discards cannot be used:
var _ = 42;
_ = "hello"; // error - a string cannot explicitly convert from string to int
The exception to this is when a _
variable is used as an out variable. In this case, the compiler ignores the type or var
and treats it as a discard:
if (p.GetCoordinates(out double x, out double _))
{
_ = "hello"; // works fine.
Console.WriteLine(_); // error: _ doesn't exist in this context.
}
Note that this only occurs if, in this case, out var _
or out double _
is used. Just use out _
and then it's treated as a reference to an existing variable, _
, if it's in scope, eg:
string _;
int.TryParse("1", out _); // complains _ is of the wrong type
Finally, the *
notation was proposed early in the discussions around discards, but was abandoned in favour of _ due to the latter being a more commonly used notation in other languages.
Another example of the Discard Operator _
in C# 7 is to pattern match a variable of type object
in a switch
statement, which was recently added in C# 7:
Code:
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
}
This code will match the type and discard the variable passed to the case ... _
.
Q: ... we can do so in pre C#7.0 too:
var _;
if (Int.TryParse(str, out _))
or am I missing something here?
That isn't the same thing.
Your code is making an assignment.
In C# 7.0 _ is not a variable, it tells the compiler to discard the value
(unless you have declared _ as a variable... if you do that the variable is used instead of the discard symbol)
Example: you can use _ as a sting and an int in the same line of code:
string a;
int b;
Test(out a, out b);
Test(out _, out _);
//...
void Test(out string a, out int b)
{
//...
}