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

Ale*_*ese 28 c# pattern-matching c#-7.0 visual-studio-2017

我已将项目升级到目标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;
    }
}
Run Code Online (Sandbox Code Playgroud)

无论是if语句和case声明产生一个编译错误.

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

如果我首先转换参数以键入object模式匹配按预期工作.罗斯林然后将演员标记object为多余.

if ((object)packet is KeepalivePacket keepalive)
{
    // This works
}
Run Code Online (Sandbox Code Playgroud)

此错误仅适用于通用参数和变量.Roslyn似乎不知道这个问题,因为它建议更改代码以通过分析器使用模式匹配,并允许我应用"代码修复"导致代码损坏.

Ale*_*ese 20

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

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

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

更新

现在正在使用C#7.1


Nat*_*ook 6

C#7.1现在支持此功能。例如,请参阅“与泛型模式匹配” 这篇文章。您可能需要在项目文件中添加<LangVersion>7.1</LangVersion><LangVersion>latest</LangVersion>。有关配置的详细信息,请参见此处LangVersion


Cer*_*vEd 5

C#7.0 的答案是

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

switch ((Packet)packet)
{
    case KeepalivePacket keepalivePacket:
        // Do stuff with keepalivePacket
        break;
}
Run Code Online (Sandbox Code Playgroud)

  • 不知道为什么这被否决了,如果你被困在 C#7.0 上,这就是你必须解决它的方法。如果您能够使用更现代的 C# 版本,那么请务必像使用普通语言一样使用模式匹配 (2认同)