简体   繁体   中英

Can I simplify this C# 7 switch statement to not re-state the type?

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.

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):

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

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; 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM