私はいつもそれが両方の方法でうまくいくと思っていました。次に、このテストを実行し、再割り当てでは許可されていないことに気付きました。
int[] a = {0, 2, 4, 6, 8};
正常に動作しますが、動作しません:
int [ ] a;
a = { 0, 2, 4, 6, 8 };
これの技術的な理由はありますか?この振る舞いは直感的に期待していたので、ここで聞いてみようと思いました。
私はいつもそれが両方の方法でうまくいくと思っていました。次に、このテストを実行し、再割り当てでは許可されていないことに気付きました。
int[] a = {0, 2, 4, 6, 8};
正常に動作しますが、動作しません:
int [ ] a;
a = { 0, 2, 4, 6, 8 };
これの技術的な理由はありますか?この振る舞いは直感的に期待していたので、ここで聞いてみようと思いました。
まず、用語を正しくしましょう。これはコレクションの初期化子ではありません。これは配列初期化子です。コレクション初期化子は、常にコレクション型のコンストラクターに従います。配列初期化子は、ローカル宣言またはフィールド宣言初期化子、あるいは配列作成式でのみ有効です。
これは奇妙なルールであることに注意するのは完全に正しいです。その奇妙さを正確に特徴づけさせてください:
intの配列を受け取るメソッドMがあるとします。これらはすべて合法です。
int[] x = new[] { 10, 20, 30 };
int[] y = new int[] { 10, 20, 30 };
int[] z = new int[3] { 10, 20, 30 };
M(new[] { 10, 20, 30 });
M(new int[] { 10, 20, 30 });
M(new int[3] { 10, 20, 30 });
だが
int[] q = {10, 20, 30}; // legal!
M( { 10, 20, 30 } ); // illegal!
「唯一の」配列初期化子は、「装飾された」配列初期化子がどこにあっても合法であるか、どこにも合法ではないようです。初期化子でのみ有効なこの疑似式があり、式が有効である他の場所にはないのは奇妙です。
私がこの選択を批判し、擁護する前に、何よりもまず、この不一致は歴史的な事故であると言いたいと思います。それには説得力のある正当な理由はありません。コードを壊さずにそれを取り除くことができれば、そうするでしょう。しかし、できません。今日もC#を最初から設計していたら、「new」のない「唯一の」配列初期化子が有効な構文ではない可能性が高いと思います。
そこで、最初に、配列初期化子を式として許可してはならず、ローカル変数初期化子で許可する必要がある理由をいくつか説明します。次に、反対の理由をいくつか挙げます。
配列初期化子を式として許可しない理由:
{
配列初期化子は、常に新しいコードブロックの導入を意味するniceプロパティに違反します。入力中に解析するIDEのエラー回復パーサーは、ステートメントが不完全であることを示す便利な方法として中かっこを使用するのが好きです。あなたが見るなら:
if (x == M(
{
Q(
))
そうすれば、コードエディタはあなたがの前に行方不明であると推測するのは非常に簡単です{
。Q(
編集者は、それがステートメントの始まりであり、その終わりが欠落していると想定します。
ただし、配列初期化子が有効な式である場合は、欠落しているものがに続いている可能性があり)})){}
ますQ
。
次に、式としての配列初期化子は、すべてのヒープ割り当てのどこかに「新しい」ものがあるという優れた原則に違反しています。
配列初期化子をフィールドおよびローカル初期化子で許可する必要がある理由:
配列初期化子は、暗黙的に型指定されたローカル、匿名型、または配列の型推論の前に、v1.0で言語に追加されたことを忘れないでください。当時は、快適な「new [] {10、20、30}」構文がなかったため、配列初期化子がないと、次のように言う必要があります。
int[] x = new int[] { 10, 20, 30 };
これは非常に冗長に思えます!なぜ彼らがその「新しいint[]」をそこから出したかったのかがわかります。
あなたが言う時
int[] x = { 10, 20, 30 };
構文的にあいまいではありません。パーサーは、これが配列初期化子であり、コードブロックの先頭ではないことを認識しています(上記の場合とは異なります)。また、型があいまいでもありません。イニシャライザがコンテキストからのintの配列であることは明らかです。
そのため、この引数は、C#1.0で配列初期化子がローカルおよびフィールド初期化子で許可されていたが、式コンテキストでは許可されなかった理由を正当化します。
しかし、それは私たちが今日いる世界ではありません。今日これをゼロから設計した場合、「新しい」ものを持たない配列初期化子はおそらくないでしょう。もちろん、今日では、より良い解決策は次のとおりです。
var x = new[] { 10, 20, 30 };
その式はどのような状況でも有効です。適切と思われる場合は、ifの「宣言」側または「初期化」側のいずれかで明示的に入力するか=
、コンパイラにいずれかまたは両方の型を推測させることができます。
したがって、要約すると、そうです、配列初期化子はローカル宣言とフィールド宣言にのみ存在でき、式コンテキストには存在できないということは一貫性がありません。その10年前には正当な理由がありましたが、型推論のある現代の世界では、もはや正当な理由はあまりありません。現時点では、これは単なる歴史的な事故です。
それはほとんどです:
int [] a;// ={1,2,3,4};
a = new [] {1, 2, 3, 4};
VBでは、宣言と同じように機能し、xDが簡単になります
Dim a() As Integer '={1,2,3,4}
a = {1, 2, 3, 4}