従来のスイッチブロックにはスコープが1つあるため、次の場合はコンパイラエラー「 'message'という名前のローカル変数または関数がすでにこのスコープで定義されています」をスローします。
switch(value)
{
case 1:
string message = "Val: 1";
break;
case 2:
string message = "Val: 2";
break;
}
合理的な質問は、「なぜこれが合法ではないのか」ということです。理にかなった答えは「まあ、なぜそうあるべきなのか」です。 2つの方法のいずれかを使用できます。これは合法です:
switch(y)
{
case 1: int x = 123; ... break;
case 2: int x = 456; ... break;
}
またはこれは合法です:
switch(y)
{
case 1: int x = 123; ... break;
case 2: x = 456; ... break;
}
しかし、両方の方法を持つことはできません。 C#の設計者は、より自然な方法であると思われる2番目の方法を選択しました。
他にも良い説明があります これのように :
他のすべてのケースでは、「通常の」ローカル変数のスコープが中括弧({})で区切られたブロックであることは、もっともな理由だと思います。
では、なぜ型パターンマッチングスイッチブロックではスコープの動作が異なるのでしょうか。
Animal p = new Dog();
switch(p)
{
case Dog a:
break;
case Cat a: // Why is this legal?
break;
}
短い答えは、a
はパターン変数であり、パターン変数のスコープはそれらを含むブロックにあるためです。
たとえば、そのswitch
をif (p is Dog a) return;
で続行すると、2つのa
変数がすでに定義されているというメッセージが表示されるため、コンパイルされなくなります。これは、if
の「包含ブロック」がif
を含むブロックであるためです。ただし、caseラベルのパターン変数の場合、包含ブロックはcaseブロックです。したがって、あなたの例では、これらの2つのa
変数は別々のブロックに存在します。
詳細については、C#7ドキュメントの パターン変数のスコープ を参照してください。
スイッチの変数スコープがこのように変更された理由を理解するには、次のコードを検討してください。
switch(animal)
{
case Dog dog1 when dog1.AverageWeightKg > 20:
// do something with dog1
break;
case Dog dog2 when dog2.AverageWeightKg > 10:
// do something with dog2
break;
case Dog dog3:
// do something with dog3
break;
case Cat cat:
// do something with cat
break;
}
それらdog1
、dog2
およびdog3
変数名は本当に醜いです。したがって、C#で変数スコープの他の側面との不整合が生じた一方で、パターン変数のスコープ規則を変更することが決定されました。つまり、上記のコードをはるかにエレガントな方法で記述できます。
switch(animal)
{
case Dog dog when dog.AverageWeightKg > 20:
// do something with dog
break;
case Dog dog when dog.AverageWeightKg > 10:
// do something with dog
break;
case Dog dog:
// do something with dog
break;
case Cat cat:
// do something with cat
break;
}