Sie können in C # kein Inline-Array verwenden?


89

Stellen Sie sich vor, Sie haben das irgendwo

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

oder auch nur das

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

Dann können Sie das natürlich tun ...

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

... was toll ist. ABER. Es scheint, dass Sie dies NICHT tun können:

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

oder in der Tat vielleicht das

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

oder irgendetwas anderes, was ich versucht habe.

In der Tat (1) warum kann man das nicht tun? und (2) vermisse ich etwas, wie würden Sie das tun, wenn es einen Weg gibt?


5
Ich bin nicht sicher, ob die doppelte Frage angemessen ist. Das OP fragt nicht nach Array-Initialisierern, aber warum erkennt der Compiler das Objekt erst dann als Array, wenn es zugewiesen ist.
Ron Beyer

4
Ich bin mit der C # -Terminologie nicht vertraut, aber ich glaube, dass dies eher als Literal oder Array-Literal als als Inline bezeichnet wird .
Chi

3
Dieses syntaktische Element ist je nach Kontext, in dem es verwendet wird, ein Array-Initialisierer oder ein Sammlungsinitialisierer . In keinem Fall wird es als Ausdruck klassifiziert .
Eric Lippert

Antworten:


129

Sie müssen das Array zuerst mit erstellen new[].

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

Wie @hvd erwähnt hat, können Sie dies ohne Klammern tun (..). Ich habe die Klammern hinzugefügt, weil ich denke, dass sie besser lesbar sind.

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

Und Sie können den Datentyp angeben, new string[]wie in anderen Antworten erwähnt wurde.


Sie können dies nicht einfach tun {"a","b","c"}, da Sie sich das als eine Möglichkeit vorstellen können, das Array zu füllen, nicht es zu erstellen.

Ein weiterer Grund ist, dass der Compiler verwirrt ist und nicht weiß, was er erstellen soll, z. B. a string[]{ .. }oder aList<string>{ .. } .

Wenn Sie nur den new[]Compiler verwenden, können Sie anhand des Datentyps ( "..") wissen {..}, was Sie wollen ( string). Der wesentliche Teil ist[] , dass Sie ein Array möchten.

Sie können nicht einmal ein leeres Array mit erstellen new[].

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

13
Sie brauchen diese Klammern nicht. string letter = new[] {"a","b","c"}.AnyOne();ist in Ordnung. Wenn Sie sie wollen, wenn Sie denken, dass sie mit den Klammern besser lesbar sind, sind sie gültig, aber in diesem Fall ist es zumindest erwähnenswert, dass es eine bewusste Entscheidung von Ihrer Seite ist, dass sie nicht durch die Sprache erzwungen wurde.

Ich kenne die Syntax new [] {1,2}, aber gibt es eine noch einfachere Syntax? So etwas wie [1, 2]?
Seguso

51

(1) Warum kann man das nicht tun? {"a","b","c"}.AnyOne();

Diese Linie:

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

ist eine kurze Hand für einen äquivalenten Array-Erstellungsausdruck (unter ILSpy )

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

Dies string[] st = {"a","b","c"} kann nur zum Zeitpunkt der Deklaration verwendet werden. Sie können es nicht anderweitig verwenden. Sie können nicht einmal Folgendes tun:

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

Es wird unter Abschnitt 7.6.10.4 für den Ausdruck der Array-Erstellung in C # -Sprachspezifikationen erläutert .

Dies "{"a", "b", "c"}"allein ohne Verwendung in der Deklaration bedeutet also nichts. Daher können Sie es nicht mit Ihrer Erweiterungsmethode verwenden, da Ihre Erweiterungsmethode auf einem Array ausgeführt wird.

(2) Vermisse ich etwas, wie würden Sie das tun, wenn es einen Weg gibt?

Bereits in der Antwort von @ adricadar erwähnt , können Sie Folgendes tun:

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

oder

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

48

Ich drücke auf "Warum nicht" -Fragen zurück, weil die Antworten zunächst fast nie zufriedenstellend sind - Sie haben bereits die Antwort erhalten: "Die Funktion ist nicht so, wie Sie es möchten, weil die Spezifikation nicht sagt, was Sie sagen möchten." , was ich mir nicht besonders befriedigend vorstelle. Zweitens muss das Designteam nicht rechtfertigen, warum die Welt nicht ist wie Sie es möchten. Funktionen existieren nicht kostenlos und werden dann außerhalb der Sprache entworfen. Vielmehr müssen Features zuerst begründet und dann in entworfen werden.

Versuchen wir also, Ihre "Warum nicht" -Frage etwas klarer zu gestalten. Das vorhandene Merkmal ist "ein Array-Initialisierer kann verwendet werden (a) auf der rechten Seite der Gleichheit in einer Initialisierung oder (b) rechts von einer Objektkonstruktion vom Array-Typ." Das vorgeschlagene Merkmal ist: "Ein Array-Initialisierer kann auch als Ausdruck verwendet werden". Die Frage ist: "Welche Kritik würde Eric an dem vorgeschlagenen Feature üben?"

Die erste Kritik, die ich machen würde, ist, dass es unklar ist, was die Art des Ausdrucks ist. In einem Variableninitialisierer haben Sie den Typ der Variablen und in einem Objekterstellungsausdruck haben Sie den Typ des Objekts; Aus beiden können wir den Typ des konstruierten Arrays ableiten. Welchen Typ sollten wir ohne einen Hinweis ableiten?

In C # 1.0 wurden beim Hinzufügen dieser Funktion insgesamt null Inferenzen vom Typ Typ in der Sprache vorgenommen. Ein Designprinzip in den frühen Tagen von C # war "keine Überraschungen" und dass der Compiler nicht "zu schlau" war. Wenn der Entwickler beabsichtigt, dass ein Ausdruck von einem bestimmten Typ ist, sollte dieser Typ im Ausdruck auf irgendeine Weise offensichtlich sein. Wenn du sagst

new double[] { 1, 2, 3.4 }

es ist ziemlich klar, welcher Typ beabsichtigt ist. Ähnlich

new Animal[] { cat, dog, null }

Das vorgeschlagene Merkmal verstößt gegen dieses Prinzip. Der Ausdruck muss einen Typ haben, aber es ist keineswegs klar, in welchem ​​Typ sich das Argument befindet

M({cat, dog, null})

Außerdem: Nehmen wir an M, wir haben zwei Überladungen von , von denen eine ein Array von Animalund eine ein Array von nimmt IPet. Welche Überlastung vonM ist anwendbar? Ist eine der Konvertierungen besser als die andere? Die Arten der Elemente sind CatundDog ; Ist es sinnvoll, einen Typ abzuleiten, der dort nicht einmal vorkommt? Dies sind alles Fragen, die vom Designteam berücksichtigt werden müssen, und dies sind Fragen, die keineswegs offensichtliche Antworten haben. Das vorgeschlagene Merkmal führt uns in relativ kurzer Zeit in tiefe Gewässer.

Jetzt löst C # 3.0 dieses Problem, da C # 3.0 zahlreiche Funktionen hinzugefügt hat, bei denen der Compiler im Auftrag des Entwicklers Typen ableitet. Die früheren Prinzipien über "keine Überraschungen" und "einfache Regeln" standen im Widerspruch zu anderen Designprinzipien, die erforderlich sind, damit LINQ funktioniert. Sollte die von Ihnen vorgeschlagene Funktion in C # 3.0 hinzugefügt worden sein?

Es könnte sein. Die in C # 3.0 tatsächlich hinzugefügte Funktion war:

new[] { x, y, z }

leitet den Typ des Arrays mithilfe des Algorithmus ab: Nehmen Sie die Ausdrücke für Elemente mit Typen, bestimmen Sie, welcher dieser Typen der eindeutigste allgemeinste Typ ist, in den alle anderen Ausdrücke konvertierbar sind, und wählen Sie diesen aus, wenn ein solcher Typ vorhanden ist. Andernfalls entsteht ein Fehler,

Diese Funktion hätte weiter gelockert werden können, um die new[]Option zu aktivieren. Dies wurde nicht getan.

Wenn Sie mich im C # 3.0-Zeitrahmen gebeten hätten, die vorgeschlagene Funktion zu kritisieren, hätte ich darauf hingewiesen, dass (1) der C # 3.0-Compiler bereits in großer Gefahr war, den Zeitplan für die gesamte Version zu verschieben. Fügen wir also keine weiteren hinzu Design-, Implementierungs- und Testaufwand für eine völlig unnötige Funktion, die dem Benutzer sechs Tastenanschläge erspart , und (2) C # 3.0 fügte außerdem Sammlungsinitialisierer hinzu:

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

Warum sollte {10, 20, 30}automatisch ein Array sein ? Warum sollte es nicht ein sein List<int>? Oder einer von mehreren anderen Typen? Warum die Tendenz zu Arrays? Denken Sie daran, sobald wir uns entschieden haben, die Syntax für Arrays zu verankern, bleiben wir für immer dabei . Es kann sein , dass es nie etwas anderes ist, daher ist das vorgeschlagene Merkmal nicht nur unnötig, sondern verhindert auch mögliche zukünftige Merkmale, die plausibel erscheinen.

Zusammenfassend lässt sich sagen, dass die vorgeschlagene Funktion einige der Entwurfsprinzipien von C # 1.0 direkt verletzt hat. C # 3.0 wird dadurch nur unnötig belastet. In allen Versionen der Sprache seit C # 3.0 hat die vorgeschlagene Funktion kein gutes Argument, um zu empfehlen, Zeit, Mühe und Geld für viele andere würdigere Funktionen aufzuwenden.

Daher keine solche Funktion.


Heh, du musst ein T-Shirt mit der Aufschrift "Die Welt ist nicht so, wie du es haben willst" bedrucken lassen :)
Slugster

6
@ JoeBlow: Zunächst einmal sind Sie sehr willkommen. In Bezug auf "Warum nicht" - Ihr Kommentar veranschaulicht das Problem gut. Wenn einige Leute eine "Warum" -Frage stellen, suchen sie nach einer logischen Rechtfertigung . Einige Leute suchen nach einer pragmatischen Rechtfertigung . Und Sie suchen anscheinend nach der Zeile der Spezifikation, die die Regel beschreibt . Es ist so vage, dass es sehr schwierig ist, eine gute Antwort zu finden, die auf die Frage abzielt, die der Fragesteller tatsächlich hat. "Warum nicht" -Fragen sind noch schlimmer, weil es sich um vage Fragen zu Dingen handelt, die es gar nicht gibt .
Eric Lippert

3
@EricLippert Es ist noch schlimmer als nur die Frage nach Dingen, die möglicherweise existieren : Wenn Sie mit einem Team an Software arbeiten, verbringt das gesamte Team jeden Tag im Jahr damit, über Funktionen nachzudenken und die Konsequenzen auszugleichen . Entscheidungen werden getroffen. Feature-Anfragen und "Warum" fragen nach Begründung. Doch warum nicht bedeutet , dass jemand will nur etwas getan, was im Grunde Fragen des Urteil des Teams selbst. Schlimmer noch, die Person, die die Warum-nicht- Frage stellt, weiß normalerweise wenig über das Thema. Daher denke ich, dass es völlig fair ist , zurückzudrängen, warum nicht Fragen gestellt werden. Gute Arbeit IMO.
atlaste
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.