web-dev-qa-db-ja.com

タイプTの式は、タイプXのパターンでは処理できません

プロジェクトをターゲット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は、アナライザーを介してパターンマッチングを使用するようにコードを変更することを推奨し、「コード修正」を適用してコードが壊れるようにするため、この問題を認識していないようです。

30
Alex Wiese

Microsoftから Neal Gafterによる説明 として:

これが機能しない理由は、TからKeepalivePacketへの変換(明示的または暗黙的)が定義されていないためです。パターンマッチングは、変換の存在を必要とするキャスト演算子で定義されているため、このような変換が存在する必要があります。言語仕様とコンパイラは、変換が存在しないことに同意します。言語仕様がここに(明示的な)変換が存在しないように定義されているのは不思議に思えます。それについて何ができるかを見てみましょう。

これについてはC#7では何もしません。回避するには、コードにキャストを追加する必要があります。再帰的なパターンが得られると、これを回避するのがより困難になる可能性があります。さらに、この問題の根底にある厄介な言語ルール(つまり、TからKeepalivePacketへの変換がない)は、あまり意味がありません。

更新

これは現在C#7.1で動作しています

19
Alex Wiese

C#7.1は現在これをサポートしています。たとえば、「 この記事 」の「ジェネリックとのパターンマッチング」を参照してください。追加する必要があるかもしれません<LangVersion>7.1</LangVersion>または<LangVersion>latest</LangVersion>をプロジェクトファイルに追加します。 LangVersionの設定の詳細については こちら を参照してください。

5
Nate Cook