类型T的表达不能由类型X的模式处理

时间:2017-01-03 04:23:43

标签: c# pattern-matching visual-studio-2017 c#-7.0

我已将项目升级到目标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似乎不知道这个问题,因为它建议更改代码以通过分析器使用模式匹配,并允许我应用&#34;代码修复&#34;导致代码损坏。

3 个答案:

答案 0 :(得分:18)

来自Microsoft的explained by Neal Gafter

  

它不起作用的原因是没有从T到KeepalivePacket定义的转换(显式或隐式)。模式匹配需要存在这样的转换,因为它是根据需要转换的转换运算符来定义的。语言规范和编译器同意不存在转换。对我来说,语言规范的定义使得这里不存在(显式)转换似乎很奇怪。我们将看看我们能做些什么。

     

我们不会在C#7中对此做任何事情。您必须在代码中添加一个强制转换来解决它。一旦我们有递归模式,这可能更难以解决。此外,这个问题背后的尴尬语言规则(即没有从T转换为KeepalivePacket)并没有多大意义。

<强>更新

现在正在使用C#7.1

答案 1 :(得分:3)

C#7.1现在支持这一点。例如,请参阅this article中的“使用泛型进行模式匹配”。您可能需要将<LangVersion>7.1</LangVersion><LangVersion>latest</LangVersion>添加到项目文件中。有关配置LangVersion的详细信息,请参阅here

答案 2 :(得分:-1)

C#7.0的答案是

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

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