【问题标题】:Can I simplify this C# 7 switch statement to not re-state the type?我可以简化这个 C# 7 switch 语句以不重新声明类型吗?
【发布时间】:2017-09-10 03:42:14
【问题描述】:

我正在查看 C# 7 的新 switch 语句,虽然我可以将类型作为模式匹配的一部分进行切换,这很棒,但我想知道是否可以避免在我已经知道的情况下重新声明类型?

例子:

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

在这里,我的 case 语句重新声明了 string x,即使我打开的类型已经是一个字符串,我只关心它是 Length 还是 int.TryParses。

只是省略它不会编译:

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

所以我只是想知道是否有办法省略它,或者它只是我必须接受的模式匹配语法的一部分。

【问题讨论】:

  • 我不认为这是一个很好的模式匹配用例——一个简单的if 或三元表达式就可以了。
  • @Dai 在这种情况下,绝对是。我更多地考虑是否存在多种条件(例如,如果由于设计不良的 API 而必须打开一堆错误消息(甚至可能是本地化的错误消息))。目前,if-cascade 或谓词字典都可以使用,但新的 switch 语法是另一种可能使用的工具。

标签: c# pattern-matching c#-7.0


【解决方案1】:

您可以使用var 模式:

case var x when x.Length == 3 && int.TryParse(x, out int i):

或者甚至更好,var 带有丢弃的模式:

case var _ when s.Length == 3 && int.TryParse(s, out int i):

【讨论】:

  • 同理,out int i 可以是out var i,因为int.TryParse() 已经暗示它将返回int
  • VS语法高亮有点被discard方法弄糊涂了,它高亮_就好像它是一个关键字一样。
【解决方案2】:

不,您不能省略类型(或屏蔽类型的 var 关键字),因为它是此处模式匹配的一部分。

考虑类层次结构(这不会在C#7 中编译,但会在完全实现后在进一步的版本中编译)

class Geometry();
class Triangle(int Width, int Height, int Base) : Geometry;
class Rectangle(int Width, int Height)          : Geometry;
class Square(int width)                         : Geometry;

现在我们得到一个像这样的变量:

Geometry g = new Square(5);

现在我们对它执行switch

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

回到你的案例,考虑代码:

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

所以类型检查是模式匹配的一部分,您不能省略它(对于C#7,它只能用于打开类型,计划对C#8 提供全面支持)。示例来自here。上一步是whenexception handling in C#6 子句

【讨论】:

  • 我认为你应该更清楚一点,记录语法和类型解构语法不在 C# 7 中。
  • 就我个人而言,我不明白这是如何回答问题的,我认为 OP 已经知道模式匹配与类型的工作原理,并且特别希望简化代码,这就是为什么我没有赞成这个答案(但我也没有反对)。
  • 在OP问的问题的最后,他可以省略类型吗?我解释说不,他不能
  • FWIW,我认为这说明了为什么在语法方面制作类型信息选项会成为一个问题。 “我可以省略类型信息吗?”的答案没有”。 @svick 提供了一个很好的解决方法,
【解决方案3】:

我使用了以下内容。从美学上讲,它令人不快,但它确实有两个优点。它相当容易理解并且可以编译。 x 最终没有被使用。 switch 语句中的变量可以是虚拟变量。如果您有特别复杂的重度嵌套 if-then 代码,则可以使用此方法,并且可以更容易/阅读/理解。有人知道更好的方法吗?

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

【讨论】:

    猜你喜欢
    • 2010-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多