Reputation: 180924
I'm looking at C# 7's new switch statement, and while it's awesome that I can switch on the type as part of pattern matching, I wonder if I can avoid re-stating the type in case I already know it?
Example:
private static void BetterSwitchCase(string s)
{
switch (s)
{
case string x when x.Length == 3 && int.TryParse(x, out int i):
Console.WriteLine($"s is a string that parses to {i}");
break;
default:
Console.WriteLine("No Match.");
break;
}
}
Here, my case statement re-states string x
even though the type I'm switching on is already a string, and I only care about it's Length
and if it int.TryParse
s.
Just omitting it doesn't compile:
// Syntax error, ':' expected
case when s.Length == 3 && int.TryParse(s, out int i):
// A constant value is expected
case s when s.Length == 3 && int.TryParse(s, out int i):
So I'm just wondering if there is a way to omit it, or if it's just part of the pattern matching syntax that I have to accept.
Upvotes: 9
Views: 4039
Reputation: 629
I've used the following. Aesthetically it is displeasing, but it does have two advantages. It's fairly easy to understand and it compiles. The x ends up not being used. The variable in the switch statement can be a dummy. If you have particularly complicated heavily nested if-then code this method can be used and can be easier to /read/understand. Anyone know a better way?
switch (dummyString)
{
case string x1 when word = "entry":
DoEntry();
break;
case string x2 when word = "exit" && door="front":
DoFrontDoorExit();
break;
case string x3 when word = "exit" && door="rear":
DoRearDoorExit();
break;
case string x4 when Tomorrow() == "Tuesday":
BuyALotteryTicket()
break;
default:
break;
}
Upvotes: 0
Reputation: 28345
No, you can't omit the type (or var
keyword masking the type), as it is a part of pattern matching here.
Consider class hierarchy (this will not compile in C#7
, but will compile in further versions after full implementation)
class Geometry();
class Triangle(int Width, int Height, int Base) : Geometry;
class Rectangle(int Width, int Height) : Geometry;
class Square(int width) : Geometry;
Now we get a variable like this:
Geometry g = new Square(5);
Now we do the switch
over it:
using static System.Console;
switch (g)
{
// check that g is a Triangle and deconstruct it into local variables
case Triangle(int Width, int Height, int Base):
WriteLine($"{Width} {Height} {Base}");
break;
// same for Rectangle
case Rectangle(int Width, int Height):
WriteLine($"{Width} {Height}");
break;
// same for Square
case Square(int Width):
WriteLine($"{Width}");
break;
// no luck
default:
WriteLine("<other>");
break;
}
Back to your case, consider the code:
switch (s)
{
case string x when x.Length == 3 && int.TryParse(x, out int i):
Console.WriteLine($"s is a string that parses to {i}");
break;
// will not compile with error
// An expression of type string cannot be handled by a pattern of type int.
case int x:
break;
// will win pattern matching and print the line
// {s} is an object
case object x:
Console.WriteLine($"{s} is an object");
default:
Console.WriteLine("No Match.");
break;
}
So type checking is a part of pattern matching and you can't omit it (and for C#7
it's only available to switch on types, full support is planned for C#8
). Example was brought from here. The previous step was the when
clause for exception handling in C#6
Upvotes: 3
Reputation: 244767
You could use var
pattern:
case var x when x.Length == 3 && int.TryParse(x, out int i):
Or even better, var
pattern with a discard:
case var _ when s.Length == 3 && int.TryParse(s, out int i):
Upvotes: 8