プロジェクトをターゲット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は、アナライザーを介してパターンマッチングを使用するようにコードを変更することを推奨し、「コード修正」を適用してコードが壊れるようにするため、この問題を認識していないようです。
Microsoftから Neal Gafterによる説明 として:
これが機能しない理由は、TからKeepalivePacketへの変換(明示的または暗黙的)が定義されていないためです。パターンマッチングは、変換の存在を必要とするキャスト演算子で定義されているため、このような変換が存在する必要があります。言語仕様とコンパイラは、変換が存在しないことに同意します。言語仕様がここに(明示的な)変換が存在しないように定義されているのは不思議に思えます。それについて何ができるかを見てみましょう。
これについてはC#7では何もしません。回避するには、コードにキャストを追加する必要があります。再帰的なパターンが得られると、これを回避するのがより困難になる可能性があります。さらに、この問題の根底にある厄介な言語ルール(つまり、TからKeepalivePacketへの変換がない)は、あまり意味がありません。
更新
これは現在C#7.1で動作しています