web-dev-qa-db-ja.com

null許容型のパターンマッチングで構文エラーが発生するのはなぜですか?

pattern-matchingnullable intを使用するのが好きです。つまり、int?

int t  = 42;
object tobj = t;    
if (tobj is int? i)
{
    System.Console.WriteLine($"It is a nullable int of value {i}");
}

ただし、これにより、次の構文エラーが発生します。

「i)」は赤い波線でマークされています。

古い演算子isを使用すると、式がコンパイルされます。

int t = 42;
object tobj = t;    
if (tobj is int?)
{
    System.Console.WriteLine($"It is a nullable int");
}


string t = "fourty two";
object tobj = t;
if (tobj is string s)
{
    System.Console.WriteLine($@"It is a string of value ""{s}"".");
}

また、期待どおりに動作します。

(私は c#-7.2 を使用しており、 。net-4.7.1。net-4.6の両方でテストしています.1

演算子の優先順位と関係があると思いました。したがって、私はいくつかの場所で括弧を使用しようとしましたが、これは役に立ちませんでした。

なぜこれらの構文エラーが発生するのですか?どうすればそれらを回避できますか?

15

コードを次のように変更します。

int t = 42;
object tobj = t;
if (tobj is Nullable<int> i)
{
    Console.WriteLine($"It is a nullable int of value {i}");
}

これにより、より役立つものが生成されます。

  • CS8116:null許容型「int?」を使用することは違法です。パターンで;代わりに基になる型 'int'を使用してください (参照するCS8116に関するドキュメントが見つかりませんでした)

その他(ユーザー @ Blue0500 at github )は、この動作をバグ Roslynの問題#20156 としてタグ付けしています。 Roslyn issue#20156 に反応して、Microsoftの Julien Couvreur は、それは仕様によるものだと考えていると述べています。
Roslynに取り組んでいるMicrosoftのNeal Gafter も、 null許容型の使用にはより良い診断が必要であると述べています

したがって、エラーメッセージは次を使用して回避できます。

int t = 42;
object tobj = t;
if (tobj == null)
{
    Console.WriteLine($"It is null");
}
else if (tobj is int i)
{
    Console.WriteLine($"It is a int of value {i}");
}

解析時の 問題tobj is int? iを除いて、なぜtobj is int? iまたはtobj is Nullable<int> iが許可されないのかという疑問が残ります。

3

Nullableでパターンマッチングを実際に使用する方法を知りたい人は、次のような一般的なヘルパー関数を使用して行うことができます。

_public static bool TryConvert<T>(object input, out T output)
{
    if (input is T result)
    {
        output = result;
        return true;
    }
    output = default(T);
    // Check if input is null and T is a nullable type.
    return input == null && System.Nullable.GetUnderlyingType(typeof(T)) != null;
}
_

trueTに含まれるのと同じタイプのnull許容または非null可能である場合、またはinputがnullでinputがnull可能である場合、これはTを返します。基本的には通常と同じように機能しますが、null許容型も処理します。


補足:興味深いことに、私のテストから、Tがnull許容の場合、System.Nullable.GetUnderlyingType(typeof(T))が呼び出されるたびに40バイトのガベージが割り当てられることがわかりました。理由はわかりませんが、私にはバグのように思えますが、通常のように単にnullチェックするのではなく、多額の費用がかかる可能性があります。

それを知って、ここにもっと良い関数があります:

_public static bool TryConvert<T>(object input, out T? output) where T : struct
{
    if (input is T result)
    {
        output = result;
        return true;
    }
    output = default(T?);
    return input == null;
}
_
2
Tim