Dela via


Måltypade new uttryck

Notera

Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.

Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader samlas in i de relevanta LDM-anteckningar (Language Design Meeting).

Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.

Champion-problem: https://github.com/dotnet/csharplang/issues/100

Sammanfattning

Kräv inte typspecifikation för konstruktorer när typen är känd.

Motivation

Tillåt fältinitiering utan att duplicera typen.

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

Tillåt att typen utelämnas när den kan härledas från användning.

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

Instansiera ett objekt utan att stava ut typen.

private readonly static object s_syncObj = new();

Specifikation

En ny syntaktisk form, target_typed_new av object_creation_expression accepteras där typen är valfri.

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?
    ;

Ett target_typed_new uttryck har ingen typ. Det finns dock en ny objektgenereringskonvertering som är en implicit konvertering från ett uttryck, och som finns från en target_typed_new till varje typ.

Med en måltyp Tär typen T0 den underliggande typen för Tom T är en instans av System.Nullable. Annars är T0T. Innebörden av ett target_typed_new uttryck som konverteras till typen T är samma som innebörden av en motsvarande object_creation_expression som anger T0 som typ.

Det är ett kompileringsfel om en target_typed_new används som en operand av en unary- eller binär operator, eller om den används där den inte är föremål för en konvertering av objektskapande.

Öppet problem: ska vi tillåta ombud och tupplar som måltyp?

Ovanstående regler omfattar delegater (en referenstyp) och tupplar (en strukttyp). Även om båda typerna är konstruktionsbara kan du redan använda en anonym funktion eller en tuppelliteral om typen kan härledas.

(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

Diverse

Följande är konsekvenserna av specifikationen:

  • throw new() tillåts (måltypen är System.Exception)
  • Måltypade new tillåts inte med binära operatorer.
  • Det är inte tillåtet när det inte finns någon typ att rikta: unära operatorer, samling av en foreach, i en using, i en dekonstruktion, i ett await-uttryck, som en anonym typ-egenskap (new { Prop = new() }), i en lock-instruktion, i en sizeof, i en fixed-instruktion, i en medlemsåtkomst (new().field), i en dynamiskt skickad åtgärd (someDynamic.Method(new())), i en LINQ-fråga, som operand till is-operatören, som den vänstra operanden till ??-operatören, ...
  • Det är också otillåtet som en ref.
  • Följande typer av typer tillåts inte som mål för konverteringen
    • Uppräkningstyper:new() fungerar (eftersom new Enum() fungerar för att ge standardvärdet), men new(1) fungerar inte eftersom uppräkningstyper inte har någon konstruktor.
    • Gränssnittstyper: Detta skulle fungera på samma sätt som motsvarande skapandeuttryck för COM-typer.
    • matristyper: matriser behöver en särskild syntax för att ange längden.
    • dynamisk: tillåter vi inte new dynamic(), så vi tillåter inte new() med dynamic som måltyp.
    • tupplar: Dessa har samma betydelse som skapandet av ett objekt med hjälp av den underliggande typen.
    • Alla andra typer som inte är tillåtna i object_creation_expression undantas också, till exempel pekartyper.

Nackdelar

Det fanns vissa oro över att måltypade new:s skapande av nya kategorier av avbrottsförändringar, men vi har redan sådana med null och default, och det har inte varit ett betydande problem.

Alternativ

De flesta klagomål om att typer är för långa för att dupliceras i fältinitiering handlar om typargument inte själva typen, vi kan bara härleda argument som new Dictionary(...) (eller liknande) och härleda typargument lokalt från argument eller insamlingsinitiatorn.

Frågor

  • Ska vi förbjuda användning i uttrycksträd? (nej)
  • Hur interagerar funktionen med dynamic argument? (ingen särskild behandling)
  • Hur ska IntelliSense fungera med new()? (endast när det finns en enda måltyp)

Designa möten