次のコードを考えます:
_string someString = null;
switch (someString)
{
case string s:
Console.WriteLine("string s");
break;
case var o:
Console.WriteLine("var o");
break;
default:
Console.WriteLine("default");
break;
}
_
なぜswitchステートメントが_case var o
_で一致するのですか?
_case string s
_は(事実上)_s == null
_がfalseと評価されるため、_(null as string) != null
_が一致しないことを理解しています。 VS CodeのIntelliSenseは、o
もstring
であることを教えてくれます。何かご意見は?
似たもの: C#7 nullチェック付きスイッチケース
明示的な型にswitch
を使用するcase
ステートメントに一致するパターン内では、問題の値がその特定の型か派生型かを尋ねています。 is
とまったく同じです
switch (someString) {
case string s:
}
if (someString is string)
値null
には型がないため、上記の条件のいずれも満たしていません。どちらの例でも、someString
の静的型は役に立たない。
ただし、パターンマッチングではvar
タイプはワイルドカードとして機能し、null
を含むすべての値と一致します。
ここでのdefault
ケースはデッドコードです。 case var o
は、nullまたは非nullの任意の値に一致します。デフォルト以外の場合は常にデフォルトの場合よりも優先されるため、default
はヒットしません。 ILを見ると、放出されていないことがわかります。
一見すると、これが警告なしにコンパイルされるのは奇妙に思えるかもしれません(間違いなく私を捨てました)。ただし、これは1.0に戻るC#の動作と一致しています。コンパイラーは、ヒットしないことを自明に証明できる場合でも、default
の場合を許可します。例として、次のことを検討してください。
bool b = ...;
switch (b) {
case true: ...
case false: ...
default: ...
}
ここでは、default
はヒットしません(1または0以外の値を持つbool
であっても)。しかし、C#は警告なしで1.0からこれを許可しています。ここでのパターンマッチングは、この動作と一致しています。
ここで複数のTwitterコメントをまとめています。これは実際には私にとって初めてのことであり、jaredparがより包括的な回答でジャンプすることを望んでいますが、私が理解しているように短いバージョン:
_case string s:
_
if(someString is string) { s = (string)someString; ...
またはif((s = (someString as string)) != null) { ... }
として解釈されます-どちらもnull
テストを含みます-あなたの場合は失敗します;逆に:
_case var o:
_
ここで、コンパイラはo
をstring
として解決しますo = (string)someString; ...
-null
テストなし、にもかかわらず似ているという事実表面的には、型を提供するコンパイラーだけで。
最後に:
_default:
_
ここではに到達できません。上記のケースがすべてをキャッチするためです。これは、到達不能コードの警告を出さなかったという点で、コンパイラのバグである可能性があります。
私はこれが非常に微妙で微妙で、混乱していることに同意します。しかし、明らかに_case var o
_シナリオはnull伝播(_o?.Length ?? 0
_など)で使用します。 _var o
_と_string s
_の間でこれがうまく機能するのは奇妙だと思いますveryします。
その理由は case <Type>
は、静的(コンパイル時)タイプではなく、動的(実行時)タイプに一致します。 null
には動的タイプがないため、string
に一致しません。 var
は単なるフォールバックです。
(短い回答が好きなので投稿)