我已将项目升级到目标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;导致代码损坏。
答案 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;
}