14

私はいつもそれがうまく両方の方法で働いたと思った。そして、このテストを行なったし、それが再割り当てで許可されていない実現:再割り当てのコレクション初期化が許可されないのはなぜですか?

int[] a = {0, 2, 4, 6, 8}; 

が正常に動作しますが、ない:

int [ ] a; 
a = { 0, 2, 4, 6, 8 }; 

このための任意の技術的な理由?この行動は私が直感的に予想したものなので、私はここでそれについて尋ねると思った。

+4

この情報は役に立ちましたでしょうか:http://stackoverflow.com/questions/7351453/why-cant-i-use-the-array-initializer-with-an-implicitly-typed-variable(厳密には複製ではありません) –

答えて

20

まずオフと同じように動作します、の条件が正しい取得してみましょう。これはコレクションイニシャライザではありません。これは配列の初期化子です。コレクション初期化子は常にコレクション型のコンストラクタに従います。配列初期化子は、ローカルまたはフィールド宣言初期化子、または配列作成式でのみ有効です。

これは奇妙な規則であることに完全に忠実です。

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! 

いずれかの「孤独」配列初期化子は「飾ら」1はどこにもない、またはことをどこでも法的であるべきように思え。これは奇妙です。この疑似式はイニシャライザでのみ有効ですが、他の式では有効ではありません。

私がこの選択を批判して守る前に、私はこの矛盾が歴史的事故であることをまず挙げておきたいと思います。それには説得力のある理由がありません。私たちがコードを破ることなくそれを取り除くことができれば、私たちはそうするでしょう。しかし、私たちはできません。今日私はC#を最初から設計していましたが、 "新しい"のない "孤独な"配列初期化子が有効な構文ではないということは間違いないと思います。

最初に、配列初期化子を式として使用できないようにし、ローカル変数初期化子で許可する必要がある理由をいくつか挙げておきます。それから私はその反対の理由をいくつか挙げます。なぜ、配列初期化子は、式として許されるべきではない

理由:

配列初期化子は{は常にコードの新しいブロックの導入を意味する素敵な財産を侵害します。入力中にパーズするIDEのエラーリカバリパーサーは、ステートメントが不完全なときに便利な方法として中カッコを使用するのが好きです。あなたが見る場合:

if (x == M(
{ 
    Q(

をコードエディタを使用すると、{))が欠落していることを推測するためにそれからそれは非常に簡単です。エディターはQ(がステートメントの始まりであり、その終わりがないと仮定します。

しかし、配列初期化子は、法的表現されている場合、それが欠けているものそれはQ)})){}である可能性があります。

第2に、式としての配列初期化子は、すべてのヒープ割り当てがどこかに「新しい」という素晴らしい原則に違反します。配列初期化子は、フィールドとローカル初期化子で許可されるべき理由

理由:

は、その配列初期化子を覚えては暗黙的に型指定された地元の人々、匿名型、またはアレイ上型推論の前に、v1.0の言語に追加されました。戻る日に、私たちは持っていなかった楽しい「新しい[] {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 }; 

この表現は任意のコンテキストで有効です。コンパイル時には、コンパイラにどちらか一方または両方の型を推測させることができます。=の "宣言"側または "初期化子"側に明示的に入力することができます。

したがって、配列の初期化子はローカルとフィールドの宣言のみで、式のコンテキストでは使用できないということは間違いありません。 10年前には正当な理由がありましたが、タイプの推論のある現代の世界では、もはや正当な理由はそれほどありません。この時点では歴史的事故に過ぎません。

+4

うわー。あなたがすべてのC#質問への回答を投稿した場合、StackOverflowは1000倍優れています。 –

+0

@JimSchubert:私は感情を非常に感謝しますが、私はそれが悪化することをお約束します。私はサイト上のC#の質問の99%に対する答えを知らない!私は言語の歴史、デザイン、実装についての専門家です。過去6年間はそれに焦点を当てています。実際には、私は何も知らない、実際のC#プログラミングの巨大な領域があることを意味しています。 –

+0

とにかく、あなたの答えを読んでください! – Matthias

1

それは可能最も:VBで

int [] a;// ={1,2,3,4}; 
    a = new [] {1, 2, 3, 4}; 

宣言、容易にxDさん

Dim a() As Integer '={1,2,3,4} 
a = {1, 2, 3, 4} 
+1

彼はなぜこの制限が存在するのか尋ねています。 –

+0

ありがとうございます。前に 'new []'を追加して動作させています。しかし、なぜこの制限がなくても(最初に割り当てたときと同じように) –

+0

VBでそれを行うことができるので、それは単なる言語のためだと思います。私たちはMSILコードを見て、diference 。 – Piyey

関連する問題