在使用复合 if 语句和带有 fall-through 的 switch 语句中进行模式匹配

6
如果我有一个if语句,类似于if (currentShape is ITable table || currentShape is AutoShape autoShape),我不能在语句块中使用table或者autoShape因为我会得到一个CS0165编译器错误
对于有穿透的switch语句也是如此。
void Foo(object o)
{
    switch (o)
    {
        case int i:
        case string s:
        case Guid g:
            string bar = i?.ToString() ?? s?.ToString() ?? g.ToString(); // cannot use i, s, or g.
            break;
    }
}

我明白为什么会这样,但我想知道,这是模式匹配的限制吗?即,您不能在复合if语句中使用它,还是有一种正确的构造语句的方法,可以使用任何一个变量(例如通过将它们初始化为null,以便至少进行空检查)?


2
也许这与 https://dev59.com/kFYO5IYBdhLWcg3wKOft 有关。如果您不想在当前区域创建垃圾本地变量,可以使用占位符。然后,您可以直接使用切换变量。 - Gaurav Chaudhary
2个回答

6
自 C# 9 开始,您可以在 switch 语句中执行以下操作:
switch (o)
{
    case object probe when probe is int or string or Guid:
        string bar = probe.ToString();
        break;
}    

并且使用开关表达式

var bar = o switch
{
    int or string or Guid => o.ToString() 
};

5
如果确实有两个不同的目标要达成,不要合并模式表达式。两个独立的 if 语句会更好地发挥作用。
if (currentShape is ITable table)
{
    // do something with tables
}

if (currentShape is AutoShape autoShape)
{
    // do something with autoshapes
}

然而,您提供的另一个例子表明这些条件之间可能存在一些共同功能。ToString() 可能是不好的示例,因为您可以使用以下代码:
string? bar = o.ToString(); // doesn't matter the type of object

但假设你希望根据类型应用不同的格式。在这种情况下,可以使用switch表达式。例如:

string? bar =
    o switch
    {
        int i => i.ToString("D3"), // three digits
        Guid g => g.ToString("N"), // no hyphens
        string s => s,    // no need to call ToString on a string
        _ => o.ToString() // all other types
    };

您还问到是否可以将变量初始化为null,以便进行null检查。对于像int这样的非可空类型,这不起作用。对于可为空的类型,它会导致一个多余的比较操作(首先测试类型并赋值为null,第二个测试是否为null)。保持表达式分离可以确保最小数量的操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接