Condividi tramite


Espressioni tipate di destinazione new

Nota

Questo articolo è una specifica di funzionalità. La specifica funge da documento di progettazione per la funzionalità. Include le modifiche specifiche proposte, insieme alle informazioni necessarie durante la progettazione e lo sviluppo della funzionalità. Questi articoli vengono pubblicati fino a quando le modifiche specifiche proposte non vengono completate e incorporate nella specifica ECMA corrente.

Potrebbero verificarsi alcune discrepanze tra la specifica di funzionalità e l'implementazione completata. Quelle differenze vengono acquisite nelle note pertinenti ai language design meeting (LDM).

Altre informazioni sul processo per l'adozione di speclet di funzionalità nello standard del linguaggio C# sono disponibili nell'articolo sulle specifiche di .

Problema del campione: https://github.com/dotnet/csharplang/issues/100

Sommario

Non richiedere la specifica del tipo per i costruttori quando il tipo è noto.

Motivazione

Consenti inizializzazione dei campi senza duplicare il tipo.

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

Consente di omettere il tipo quando può essere dedotto dall'utilizzo.

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

Creare un'istanza di un oggetto senza specificare il tipo.

private readonly static object s_syncObj = new();

Specificazione

Viene accettata una nuova forma sintattica, target_typed_new del object_creation_expression in cui il tipo è facoltativo.

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

Un'espressione target_typed_new non dispone di un tipo. Tuttavia, esiste una nuova conversione di creazione di oggetti che è una conversione implicita da un'espressione, che va da un target_typed_new a ogni tipo.

Dato un tipo di destinazione T, il tipo T0 è il tipo sottostante di Tse T è un'istanza di System.Nullable. In caso contrario, T0 è T. Il significato di un'espressione target_typed_new convertita nel tipo T corrisponde al significato di un object_creation_expression corrispondente che specifica T0 come tipo.

Si tratta di un errore in fase di compilazione se un target_typed_new viene usato come operando di un operatore unario o binario o se viene usato in cui non è soggetto a una conversione di creazione di oggetti .

Problema aperto: dovremmo consentire delegati e tuple come tipo obiettivo?

Le regole precedenti includono delegati (un tipo di riferimento) e tuple (un tipo struct). Anche se entrambi i tipi sono costruttibili, se il tipo è inferibile, è già possibile usare una funzione anonima o un valore letterale di tupla.

(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

Misto

Di seguito sono riportate le conseguenze della specifica:

  • throw new() è consentito (il tipo di destinazione è System.Exception)
  • L'new tipizzato di destinazione non è consentito con operatori binari.
  • Non è consentito quando non esiste alcun tipo di destinazione: operatori unari, raccolta di un foreach, in un using, in una decostruzione, in un'espressione await, come proprietà di tipo anonimo (new { Prop = new() }), in un'istruzione lock, in un sizeof, in un'istruzione fixed, in un accesso membro (new().field), in un'operazione gestita dinamicamente (someDynamic.Method(new())), in una query LINQ, come operando dell'operatore is, come operando sinistro dell'operatore ??, ...
  • Non è consentito anche come ref.
  • I tipi seguenti non sono consentiti come destinazioni della conversione
    • tipi di enumerazione:new() funzionerà (come new Enum() funziona per assegnare il valore predefinito), ma new(1) non funzionerà poiché i tipi di enumerazione non dispongono di un costruttore.
    • Tipi di interfaccia: questa operazione funziona come l'espressione di creazione corrispondente per i tipi COM.
    • Tipi di matrice: matrici necessitano di una sintassi speciale per fornire la lunghezza.
    • dinamica: non consentiamo new dynamic(), quindi non consentiamo new() con dynamic come tipo di destinazione.
    • tuple: hanno lo stesso significato della creazione di un oggetto usando il tipo sottostante.
    • Tutti gli altri tipi non consentiti nel object_creation_expression vengono esclusi anche, ad esempio, tipi di puntatore.

Svantaggi

Ci sono state alcune preoccupazioni riguardo alla creazione di nuove categorie di modifiche significative con il tipo di destinazione new, ma questo lo avevamo già con null e default, e non è stato un problema significativo.

Alternative

La maggior parte delle lamentele relative ai tipi troppo lunghi da duplicare nell'inizializzazione dei campi riguarda gli argomenti di tipo , non il tipo stesso; potremmo dedurre solo argomenti di tipo come new Dictionary(...) (o simili) e dedurre localmente gli argomenti di tipo dagli argomenti o dall'inizializzatore della raccolta.

Domande

  • È consigliabile proibire gli utilizzi negli alberi delle espressioni? (no)
  • In che modo la funzionalità interagisce con gli argomenti dynamic? (nessun trattamento speciale)
  • Come funziona IntelliSense con new()? (solo quando è presente un singolo tipo di destinazione)

Riunioni di design