类型为T的表达式无法被类型为X的模式处理。

39
我已将我的项目升级为目标C# 7,并使用Visual Studio 2017 RC实现了整个解决方案中的模式匹配。在这样做后,一些与泛型参数相关的模式匹配错误被引入。
请考虑以下代码:
public class Packet
{
}

public class KeepalivePacket : Packet
{
}

public void Send<T>(T packet)
    where T : Packet
{
    if (packet is KeepalivePacket keepalive)
    {
        // Do stuff with keepalive
    }

    switch (packet)
    {
        case KeepalivePacket keepalivePacket:
            // Do stuff with keepalivePacket
            break;
    }
}

if语句和case语句都会产生编译错误。

类型为T的表达式无法被类型为KeepalivePacket的模式处理。

如果我首先将参数强制转换为object类型,则模式匹配按预期工作。 Roslyn随后将object的强制转换标记为冗余。

if ((object)packet is KeepalivePacket keepalive)
{
    // This works
}

这个错误似乎只适用于泛型参数和变量。Roslyn似乎没有意识到这个问题,因为它建议通过分析器更改代码以使用模式匹配,并允许我应用“代码修复”,导致代码出错。


如果你必须根据对象的类型进行切换,那么这看起来像是糟糕的设计。实际上,一些人认为is运算符已经成为了坏味道... - Willem Van Onsem
6
@WillemVanOnsem,肯定有足够的模式匹配使用案例让C#团队将其添加到规范中,不是吗? - Alex Wiese
实际上,大多数工业应用程序都不能先设计整个系统,因为它们太复杂了。但是,实际上每个is运算符等最好都由动态绑定替换,因为这些更具类型安全性。 - Willem Van Onsem
6
@WillemVanOnsem 我明白了,你能否给我一个将C#中的is/as运算符替换为动态绑定的例子呢?或者你是在指动态分派吗?针对上面的代码,数据包是由序列化器返回的,并且通过根据类型进行开关来实现控制流程。 - Alex Wiese
3个回答

26

正如微软的 Neal Gafter 所 解释 的那样:

它不起作用的原因是没有从 T 到 KeepalivePacket 定义的转换(显式或隐式)。模式匹配需要这样的转换存在,因为它是根据强制类型转换运算符定义的,而强制类型转换运算符需要存在一种转换。语言规范和编译器都认为不存在这样的转换。对我来说,似乎很奇怪,语言规范被定义为在此处不存在(显式)转换。我们将看看我们能在这方面做些什么。

在 C# 7 中,我们不会对此进行任何处理。您需要向代码添加一个转换以解决此问题。一旦我们拥有递归模式,这可能更难解决。此外,导致这个问题的尴尬语言规则(即从 T 到 KeepalivePacket 没有转换)并没有太多意义。

更新

在 C# 7.1 中已经可以使用了。


12

C# 7.1 现在已经支持了此功能。例如,查看此文章中的 "通用模式匹配" 部分。您可能需要在项目文件中添加 <LangVersion>7.1</LangVersion><LangVersion>latest</LangVersion>。有关配置 LangVersion 的详细信息,请参见这里


4

C#7.0的答案是

if ((Packet)packet is KeepalivePacket keepalive)
{
    // Do stuff with keepalive
}

switch ((Packet)packet)
{
    case KeepalivePacket keepalivePacket:
        // Do stuff with keepalivePacket
        break;
}

2
不确定为什么被踩了,如果你卡在C#7.0上,那么这就是解决方法。如果你能使用更现代的C#版本,那么请随意使用模式匹配,就像在普通语言中一样。 - CervEd
1
你的解决方案与我们的情况相吻合。我们现在卡在第7步,所以你的答案非常有用。现在问题仍然存在,就是为什么需要首先安排这个安排...但那是另一天的问题...我还没有找到确切的原因...所以那个技术债务可以去银行并产生利息。(非常自知地意识到我的代码不是最好的。;D) - Hunter-Orionnoir

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