Freigeben über


Zieltypisierte new-Ausdrücke

Anmerkung

Dieser Artikel ist eine Featurespezifikation. Die Spezifikation dient als Designdokument für das Feature. Es enthält vorgeschlagene Spezifikationsänderungen sowie Informationen, die während des Entwurfs und der Entwicklung des Features erforderlich sind. Diese Artikel werden veröffentlicht, bis die vorgeschlagenen Spezifikationsänderungen abgeschlossen und in die aktuelle ECMA-Spezifikation aufgenommen werden.

Es kann einige Abweichungen zwischen der Featurespezifikation und der abgeschlossenen Implementierung geben. Diese Unterschiede werden in den entsprechenden Hinweisen zum Language Design Meeting (LDM) erfasst.

Weitere Informationen zum Einführen von Featurespezifikationen in den C#-Sprachstandard finden Sie im Artikel zu den Spezifikationen.

Champion Issue: https://github.com/dotnet/csharplang/issues/100

Zusammenfassung

Geben Sie keine Typspezifikation für Konstruktoren an, wenn der Typ bekannt ist.

Motivation

Die Feldinitialisierung zulassen, ohne den Typ zu duplizieren.

Dictionary<string, List<int>> field = new() {
    { "item1", new() { 1, 2, 3 } }
};

Lassen Sie das Auslassen des Typs zu, wenn er von der Verwendung abgeleitet werden kann.

XmlReader.Create(reader, new() { IgnoreWhitespace = true });

Instanziieren Sie ein Objekt, ohne den Typ anzugeben.

private readonly static object s_syncObj = new();

Spezifikation

Eine neue syntaktische Form, target_typed_new des object_creation_expression wird akzeptiert, bei der der type optional ist.

object_creation_expression
    : 'new' type '(' argument_list? ')' object_or_collection_initializer?
    | 'new' type object_or_collection_initializer
    | target_typed_new
    ;
target_typed_new
    : 'new' '(' argument_list? ')' object_or_collection_initializer?
    ;

Ein target_typed_new Ausdruck hat keinen Typ. Es gibt jedoch eine neue Objekterzeugung Konversion, die eine implizite Konversion von Ausdruck ist, die von einem target_typed_new zu jedem Typ existiert.

Für einen Zieltyp Tist der Typ T0 der zugrundeliegende Typ von T, wenn T eine Instanz von System.Nullableist. Andernfalls wird T0T. Die Bedeutung eines target_typed_new Ausdrucks, der in den Typ konvertiert wirdT entspricht der Bedeutung einer entsprechenden object_creation_expression, die T0 als Typ angibt.

Es handelt sich um einen Kompilierungsfehler, wenn ein target_typed_new als Operand eines unären oder binären Operators verwendet wird, oder wenn er dort benutzt wird, wo er nicht einer Objekterstellungskonvertierungunterliegt.

Offene Frage: Sollten wir Delegaten und Tupel als Ziel-Typ zulassen?

Die obigen Regeln schließen Delegates (ein Referenztyp) und Tuples (ein Struct-Typ) ein. Obwohl beide Typen konstruierbar sind, kann, wenn der Typ ableitbar ist, bereits eine anonyme Funktion oder ein Tupel-Literal verwendet werden.

(int a, int b) t = new(1, 2); // "new" is redundant
Action a = new(() => {}); // "new" is redundant

(int a, int b) t = new(); // OK; same as (0, 0)
Action a = new(); // no constructor found

Verschiedenes

Es folgen Folgen der Spezifikation:

  • throw new() ist zulässig (der Zieltyp ist System.Exception)
  • Der Ziel-Typ new ist bei binären Operatoren nicht zugelassen.
  • Es ist unzulässig, wenn es keinen Typ als Ziel gibt: unäre Operatoren, Sammlung eines foreach, in einem using, in einer Dekonstruktion, in einem await-Ausdruck, als anonyme Typeigenschaft (new { Prop = new() }), in einer lock-Anweisung, in einer sizeof, in einer fixed-Anweisung, in einem Mitgliedszugriff (new().field), in einer dynamisch ausgelieferten Operation (someDynamic.Method(new())), in einer LINQ-Abfrage, als Operand des is-Operators, als linker Operand des ??-Operators, ...
  • Es ist auch als ref nicht zulässig.
  • Die folgenden Arten von Typen sind nicht als Ziele der Konvertierung zulässig.
    • Enum-Typen:new() funktionieren (da new Enum() funktioniert, um den Standardwert zu geben), aber new(1) funktioniert nicht, da Enum-Typen keinen Konstruktor haben.
    • Schnittstellentypen: Dies funktioniert genauso wie der entsprechende Erstellungsausdruck für COM-Typen.
    • Array-Typen: Arrays benötigen eine spezielle Syntax, um die Länge anzugeben.
    • Dynamisch: wir lassen new dynamic() nicht zu, also bieten wir keine Möglichkeit new() mit dynamic als Zieltyp.
    • Tupel: Diese haben die gleiche Bedeutung wie eine Objekterzeugung unter Verwendung des zugrunde liegenden Typs.
    • Alle anderen Typen, die in der object_creation_expression nicht zulässig sind, werden ebenfalls ausgeschlossen, z. B. Zeigertypen.

Nachteile

Es gab einige Bedenken, dass der Zieltyp new neue Kategorien von fehlerhaften Änderungen erstellt, aber das haben wir bereits mit null und default, und das war kein großes Problem.

Alternativen

Die meisten Beschwerden darüber, dass Typen zu lang sind, um sie in der Feldinitialisierung zu duplizieren, beziehen sich auf Typargumente und nicht auf den Typ selbst. Wir könnten nur Typargumente wie new Dictionary(...) (oder ähnlich) ableiten und Typargumente lokal aus Argumenten oder dem Collection Initializer ableiten.

Fragen

  • Sollten wir Verwendungen in Ausdrucksbäumen verbieten? (nein)
  • Wie interagiert das Feature mit dynamic Argumenten? (keine Spezielle Behandlung)
  • Wie Soll IntelliSense mit new()arbeiten? (nur wenn ein einzelner Zieltyp vorhanden ist)

Planungsbesprechungen