C#で「インライン」配列を使用できませんか?


89

あなたがこれをどこかに持っていると想像してください

public static T AnyOne<T>(this T[] ra) where T:class
    {
    int k = ra.Length;
    int r = Random.Range(0,k);
    return ra[r];
    }

またはこれだけでも

public static string OneOf(this string[] strings)
    {
    return "a";
    }

その後、もちろんこれを行うことができます...

string[] st = {"a","b","c"};
string letter = st.AnyOne();

すごい・・・。だが。あなたはこれを行うことができないようです:

string letter = {"a","b","c"}.AnyOne();

または実際にこれ

string letter = ( {"a","b","c"} ).AnyOne();

または私が試した他のもの。

実際(1)なぜそれができないのですか?(2)何かが足りないのですが、道があればどうしますか?


5
重複する質問が適切であるかどうかはわかりません。OPは配列初期化子を要求していませんが、コンパイラがオブジェクトが割り当てられるまでオブジェクトを配列として認識しないのはなぜですか。
Ron Beyer

4
私はC#の用語に精通していませんが、これはインラインではなく、リテラルまたは配列リテラルと呼ばれることが多いと思います。
2015年

3
その構文要素は、それが使用されるコンテキストに応じて、配列初期化子またはコレクション初期化子です。どちらの場合もとして分類されません。
Eric Lippert、2015年

回答:


129

まず、を使用して配列を作成する必要がありますnew[]

string letter = (new[] {"a","b","c"}).AnyOne();

@hvdが括弧なしでこれを行うことができると述べたように(..)、私はそれがより読みやすいと思うので括弧を追加しました。

string letter = new[] {"a","b","c"}.AnyOne();

またnew string[]、他の回答と同様に、データ型を指定できます。


{"a","b","c"}配列を作成するのではなく、配列を作成する方法と考えることができるので、単に実行することはできません。

もう1つの理由は、コンパイラーが混乱し、何を作成するかがわからなくなるためです(たとえば、a string[]{ .. }やa)List<string>{ .. }

new[]コンパイラだけを使用すると、データ型"..")、間{..}、必要なもの()を知ることができますstring。重要な部分はです[]。つまり、配列が必要です。

で空の配列を作成することもできませんnew[]

string[] array = new []{ }; // Error: No best type found for implicity-typed array

13
これらの括弧は必要ありません。string letter = new[] {"a","b","c"}.AnyOne();大丈夫です それらが必要な場合、かっこを使用して読みやすくすると、それらは有効になりますが、その場合、言語によって強制されたのではなく、それがあなたの意識的な選択であることは少なくとも言及する価値があると思います。

構文new [] {1,2}について知っていますが、もっと簡単な構文はありますか?[1、2]のようなものですか?
seguso

51

(1)なぜそれができないのですか? {"a","b","c"}.AnyOne();

この行:

string[] st = {"a","b","c"};

同等の配列作成式の 省略形ですILSpyの下)。

string[] st = new string[]  {"a","b","c"};

これstring[] st = {"a","b","c"} は宣言時にのみ使用できます。他の場所では使用できません。使用することもできません。

string[] st;
st = {"a", "b", "c"}; //Error

これは、C#言語仕様の配列作成式のセクション7.6.10.4で説明されています。

したがって"{"a", "b", "c"}"、宣言で使用しないこれだけでは意味がありません。したがって、拡張メソッドは配列を操作するため、拡張メソッドで使用することはできません。

(2)何かが足りないのですが、道があればどうしますか?

@adricadarの回答ですでに言及されているように、次のことができます。

(new[] {"a","b","c"}).AnyOne();

または

(new string[] {"a","b","c"}).AnyOne();

48

「なぜそうでないのか」という質問は差し控えます。なぜなら、最初は答えが満足できるものではないからです。すでに「仕様はあなたが言いたいことを言っていないので、機能はあなたが望んでいる方法ではない」という答えを得ています。 、私は特に満足のいく答えではなかったと思います。第2に、デザインチームは、世界が希望どおりになっていない理由を正当化する必要はありません。機能は無料では存在せず、その言語から設計されています。むしろ、機能を最初に正当化し、次に設計する必要があります。

それでは、「なぜしない」の質問をもう少しはっきりさせてみましょう。既存の機能は、「配列初期化子は、(a)初期化でのequalsの右側、または(b)配列型のオブジェクト構築の右側で使用できます。提案された機能は、「配列初期化子も式として使用できます」です。問題は、「エリックは提案された機能に対してどのような批判をするでしょうか?」

私が最初に批判するのは、表現のタイプが何であるかがはっきりしないということです。変数初期化子には変数のタイプがあり、オブジェクト作成式にはオブジェクトのタイプがあります。これらの両方から、構築された配列のタイプを推定できます。どちらのヒントもなく、どのタイプを推測する必要がありますか?

C#1.0では、この機能が追加されたときに、言語で行われたゼロの型推論の総計がありました。C#の初期の設計原則は「驚きなし」であり、コンパイラーは「あまりにもスマート」ではありませんでした。開発者が式を特定のタイプにすることを意図している場合、そのタイプは式の中で何らかの形で明白でなければなりません。あなたが言う時

new double[] { 1, 2, 3.4 }

どのタイプが意図されているかはかなり明確です。同様に

new Animal[] { cat, dog, null }

提案された機能はこの原則に違反しています。式には型が必要ですが、引数の型が何であるかは明確ではありません

M({cat, dog, null})

さらに:の2つのオーバーロードがありM、1つはの配列を取得しAnimal、もう1つはの配列を取得するとしIPetます。どのオーバーロードMが適用可能ですか?変換の1つは他の変換よりも優れていますか?要素のタイプはCatおよびDogです。そこにさえ現れないタイプを推論することは意味がありますか?これらはすべて設計チームが考慮しなければならない質問であり、これらは決して明白な答えを持たない質問です。提案された機能は、私たちを非常に短い順序で深海に導きます。

現在、C#3.0はこの問題を解決します。C#3.0は、コンパイラーが開発者に代わって型を推論する多数の機能を追加したためです。「驚きなし」と「単純なルール」に関する以前の原則は、LINQを機能させるために必要な他の設計原則と矛盾していました。提案する機能はC#3.0で追加されたものですか?

それはあったかもしれない。C#3.0で実際に追加された機能は次のとおりです。

new[] { x, y, z }

は、アルゴリズムを使用して配列のタイプを推測します。タイプを持つ要素の式を取り、それらのタイプのどれが他のすべての式が変換可能な一意の最も一般的なタイプであるかを判別し、そのようなタイプが存在する場合はそれを選択します。そうでない場合、エラーが発生します。

その機能をさらに緩和してnew[]オプションにすることもできます。これは行われませんでした。

ここで、C#3.0の時間枠で提案された機能を批判するように依頼された場合、(1)C#3.0コンパイラはすでにリリース全体のスケジュールを延期するという重大な危険にさらされているので、これ以上追加しないでください。ユーザーに6回のキーストロークを節約する完全に不要な機能のための設計、実装、およびテストの負担、および(2)C#3.0もコレクション初期化子を追加しました。

new List<int>() { 10, 20, 30 }

なぜ{10, 20, 30}自動的に配列になるのですか?なぜそれはいけないのList<int>ですか?または、他の多くのタイプのいずれか?なぜアレイに偏っているのですか?覚えておいてください、私たちはアレイのための構文を安置することを選択した後、我々は永遠にそれで立ち往生しています。それはなることはありませんも何も提案されている機能だけでなく、不要であるので、それももっともらしく思われる可能な将来の機能を妨げ、他。

要約すると、提案された機能は、C#1.0の設計原則の一部に直接違反しています。C#3.0に不必要な負担を追加するだけです。C#3.0以降の言語のすべてのバージョンで、提案された機能は、他の多くの価値のある機能よりも時間、労力、お金を費やすことを推奨する良い議論をしていません。

したがって、そのような機能はありません。


えっと、「世界はあなたが望んでいる方法ではない」と印刷されたTシャツを入手する必要があります :)
slugster '29年

6
@JoeBlow:まず、大歓迎です。「理由」について-あなたのコメントは問題をうまく説明しています。一部の人々が「なぜ」の質問をするとき、彼らは論理的な正当化を求めています。一部の人々は実用的な正当化を探しています。そして、あなたはどうやらルールを説明する仕様の行を探しています。あいまいなので、実際に質問者の頭の中で質問を対象とする良い答えを作成することは非常に困難です。「どうして」という質問は、存在しないことについてのあいまいな質問であるため、さらに悪化ます。
Eric Lippert、2015年

3
@EricLippert _might_が存在することについて質問だけでなく、チームでソフトウェアに取り組んでいる場合、チーム全体が機能について考え、結果のバランスをとるように年間を費やしています。決定が下されます。機能のリクエストと「理由」が正当化を求めている。ただし、誰かが何かをしたいだけで、基本的にはチーム自身の判断に疑問を投げかけることを意味しません。さらに悪いことに、なぜ「しない」の質問をする人は通常、主題についてほとんど知りません。このように、私はなぜ疑問がないのかということを押し戻すのは全く公正だと思います。いい仕事IMO。
2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.