Udostępnij za pośrednictwem


Wyrażenia typu docelowego new

Notatka

Ten artykuł jest specyfikacją funkcji. Specyfikacja służy jako dokument projektowy dla funkcji. Zawiera proponowane zmiany specyfikacji wraz z informacjami wymaganymi podczas projektowania i opracowywania funkcji. Te artykuły są publikowane do momentu sfinalizowania proponowanych zmian specyfikacji i włączenia ich do obecnej specyfikacji ECMA.

Mogą wystąpić pewne rozbieżności między specyfikacją funkcji a ukończoną implementacją. Te różnice są przechwytywane w odpowiednich spotkania projektowego języka (LDM).

Więcej informacji na temat procesu wdrażania specyfikacji funkcji można znaleźć w standardzie języka C# w artykule dotyczącym specyfikacji .

Problem dotyczący czempiona: https://github.com/dotnet/csharplang/issues/100

Streszczenie

Nie wymagaj specyfikacji typu dla konstruktorów, gdy typ jest znany.

Motywacja

Zezwalaj na inicjowanie pól bez duplikowania typu.

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

Zezwalaj na pominięcie typu, gdy można go wywnioskować z użycia.

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

Utwórz wystąpienie obiektu bez określania typu.

private readonly static object s_syncObj = new();

Specyfikacja

Nowa forma składniowa target_typed_new dla object_creation_expression jest akceptowana, w której typ jest opcjonalny.

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

Wyrażenie target_typed_new nie posiada typu. Istnieje jednak nowa konwersja tworzenia obiektów, która jest niejawną konwersją z wyrażenia, umożliwiająca przejście z target_typed_new na każdy typ.

Biorąc pod uwagę typ docelowy T, typ T0 jest typem bazowym dla T, jeśli T jest wystąpieniem System.Nullable. W przeciwnym razie T0 jest T. Znaczenie wyrażenia target_typed_new konwertowanego na typ T jest takie samo jak znaczenie odpowiadającego object_creation_expression określającego T0 jako typ.

Jest to błąd czasu kompilacji, jeśli target_typed_new jest używany jako operand jednoargumentowego lub binarnego operatora, lub jeśli jest używany, gdy nie podlega konwersji tworzenia obiektu.

otwarty problem: czy należy zezwolić delegatom i krotkom na typ docelowy?

Reguły powyżej obejmują delegaty (typ odwołania) i krotki (typ struktury). Chociaż oba typy można skonstruować, jeśli typ można wywnioskować, można już użyć funkcji anonimowej lub literału krotki.

(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

Różne

Poniżej przedstawiono konsekwencje specyfikacji:

  • throw new() jest dozwolona (typ docelowy to System.Exception)
  • Typ docelowy new nie jest dozwolony w przypadku operatorów binarnych.
  • Nie jest dozwolone, gdy nie ma typu docelowego: operatory jednoargumentowe, kolekcja foreach, w using, w dekonstrukcji, w wyrażeniu await, jako właściwość typu anonimowego (new { Prop = new() }), w instrukcji lock, w instrukcji sizeof, w instrukcji fixed, w dostępie do członka (new().field), w operacji dynamicznie wysyłanej (someDynamic.Method(new())), w zapytaniu LINQ, jako operand operatora is, jako lewy operand operatora ??, ...
  • Jest również niedozwolony jako ref.
  • Następujące rodzaje typów nie są dozwolone jako obiekty docelowe konwersji
    • typy wyliczenia:new() będzie działać (ponieważ new Enum() działa, aby nadać wartość domyślną), ale new(1) nie będzie działać, ponieważ typy wyliczenia nie mają konstruktora.
    • Typy interfejsów: To działałoby tak samo jak odpowiednie wyrażenie tworzenia dla typów COM.
    • typy tablic: tablice wymagają specjalnej notacji, aby określić długość.
    • dynamiczna: nie zezwalamy na new dynamic(), więc nie zezwalamy na new() z dynamic jako typ docelowy.
    • Krotki: Mają to samo znaczenie, co tworzenie obiektu za pomocą typu bazowego.
    • Wszystkie inne typy, które nie są dozwolone w object_creation_expression, są również wykluczone, na przykład, typy wskaźników.

Wady

Wystąpiły pewne obawy związane z new przypisanym do wartości docelowych, tworząc nowe kategorie zmian niezgodności, ale mamy już to z null i default, a to nie było znaczącym problemem.

Alternatywy

Większość skarg dotyczących typów zbyt długich do zduplikowania w inicjowaniu pola dotyczy argumentów typu , a nie samego typu; możemy wywnioskować tylko argumenty typu w niektórych przypadkach, takich jak new Dictionary(...), i wywnioskować je lokalnie z kontekstu argumentów lub inicjatora kolekcji.

Pytania

  • Czy powinniśmy zabraniać użycia w drzewach wyrażeń? (nie)
  • Jak funkcja współdziała z argumentami dynamic? (bez specjalnego traktowania)
  • Jak funkcja IntelliSense powinna działać z new()? (tylko wtedy, gdy istnieje jeden typ docelowy)

Spotkania projektowe