Delen via


Doelgericht getypeerde new-uitdrukkingen

Notitie

Dit artikel is een functiespecificatie. De specificatie fungeert als het ontwerpdocument voor de functie. Het bevat voorgestelde specificatiewijzigingen, samen met informatie die nodig is tijdens het ontwerp en de ontwikkeling van de functie. Deze artikelen worden gepubliceerd totdat de voorgestelde specificaties zijn voltooid en opgenomen in de huidige ECMA-specificatie.

Er kunnen enkele verschillen zijn tussen de functiespecificatie en de voltooide implementatie. Deze verschillen worden vastgelegd in de relevante LDM-notities (Language Design Meeting).

Meer informatie over het proces voor het aannemen van functiespeclets in de C#-taalstandaard vindt u in het artikel over de specificaties.

Kampioenprobleem: https://github.com/dotnet/csharplang/issues/100

Samenvatting

Vereist geen typespecificatie voor constructors wanneer het type bekend is.

Motivatie

Initialisatie van velden toestaan zonder het type te dupliceren.

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

Hiermee staat u toe dat het type wordt weggelaten wanneer het kan worden afgeleid van het gebruik.

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

Instantieer een object zonder het type te spellen.

private readonly static object s_syncObj = new();

Specificatie

Een nieuwe syntactische vorm, target_typed_new van de object_creation_expression wordt geaccepteerd waarin het type optioneel is.

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

Een target_typed_new-expressie heeft geen type. Er is echter een nieuwe objectcreatieconversie die een impliciete conversie vanuit een expressie is, die bestaat van een target_typed_new naar elk type.

Gegeven een doeltype Tis T0 het onderliggende type van Tals T een exemplaar van System.Nullableis. Anders wordt T0T. De betekenis van een target_typed_new-expressie die wordt geconverteerd naar het type T is hetzelfde als de betekenis van een overeenkomende object_creation_expression die T0 aangeeft als het type.

Het is een compilatiefout als een target_typed_new wordt gebruikt als operand van een unaire of binaire operator, of als deze wordt gebruikt waar het niet onderworpen is aan een objectcreatieconversie .

Probleem openen: moeten we gedelegeerden en tuples toelaten als doeltype?

De bovenstaande regels omvatten delegeringen (verwijzingstypen) en tuples (structtypen). Hoewel beide typen constructeerbaar zijn, kan een anonieme functie of een letterlijke tuple al worden gebruikt als het type kan worden afgeleid.

(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

Allerlei

Dit zijn de gevolgen van de specificatie:

  • throw new() is toegestaan (het doeltype is System.Exception)
  • Doelgetypeerde new is niet toegestaan met binaire operatoren.
  • Het is niet toegestaan wanneer er geen type is om op te richten: unitaire operator, verzameling van een foreach, in een using, in een deconstructie, in een await-uitdrukking, als een eigenschap van een anoniem type (new { Prop = new() }), in een lock-instructie, in een sizeof, in een fixed-instructie, in een lidtoegang (new().field), in een dynamisch verzonden bewerking (someDynamic.Method(new())), in een LINQ-query, als operand van de operator is, als de linkeroperand van de ??-operator, ...
  • Het is ook niet toegestaan als een ref.
  • De volgende typen zijn niet toegestaan als doelen van de conversie
    • Enum-typen:new() werkt (omdat new Enum() werkt om de standaardwaarde te geven), maar new(1) werkt niet als enumtypen geen constructor hebben.
    • Interfacetypen: Dit werkt hetzelfde als de bijbehorende aanmaakexpressie voor COM-typen.
    • matrixtypen: matrices hebben een speciale syntaxis nodig om de lengte op te geven.
    • dynamisch: wij staan new dynamic()niet toe, dus wij staan new() niet toe met dynamic als doeltype.
    • tuples: Deze hebben dezelfde betekenis als het maken van een object met behulp van het onderliggende type.
    • Alle andere typen die niet zijn toegestaan in de object_creation_expression worden ook uitgesloten, bijvoorbeeld aanwijzertypen.

Nadelen

Er waren enkele zorgen over het doeltype new dat nieuwe categorieën van brekende wijzigingen creëert, maar we hebben dat al met null en default, en dat is geen groot probleem geweest.

Alternatieven

De meeste klachten over typen die te lang zijn om te dupliceren tijdens de initialisatie van velden, betreffen typeargumenten en niet het type zelf. We zouden alleen typeargumenten zoals new Dictionary(...) (of vergelijkbaar) kunnen afleiden en typeargumenten lokaal uit argumenten of de initialisatiefunctie voor verzamelingen kunnen afleiden.

Vragen

  • Moeten we het gebruik in expressiebomen verbieden? (nee)
  • Hoe de functie communiceert met dynamic argumenten? (geen speciale behandeling)
  • Hoe werkt IntelliSense met new()? (alleen wanneer er één doeltype is)

Ontwerpvergaderingen