Perché esiste un nuovo vincolo () in C # ma nessun altro vincolo simile?

18

Nei generici C #, possiamo dichiarare un vincolo per un parametro di tipo T per avere un costruttore predefinito, dicendo where T : new() . Tuttavia, nessun altro tipo di vincoli come questo è valido - new(string) per esempio, ecc.

Da una prospettiva di progettazione e / o implementazione del linguaggio, qual è la ragione di questo?

C'è qualcosa nel modo in cui i costruttori funzionano o nel modo in cui il sistema di tipi è implementato che vieta questo (o almeno lo rende più difficile)? Se è così, che cosa è? Ricordo di aver letto da qualche parte che default(T) in realtà compila a new T() per T : struct . È collegato a questo, forse?

O è semplicemente una decisione di progettazione presa per evitare di rendere il linguaggio troppo complicato?

    
posta Theodoros Chatzigiannakis 22.04.2014 - 23:51
fonte

2 risposte

4

Per una risposta autorevole, ti rimando alla risposta di Eric Lippert a quella domanda su StackOverflow alcuni anni fa, uno snippet di cui è brevemente citato di seguito.

However, in this specific case I can certainly give you some reasons why I would push back on the feature if it came up in a design meeting as a possible feature for a future version of the language.

...

I say that we should either do the whole feature or don't do it at all. If it is important to be able to restrict types to have particular constructors, then let's do the whole feature and restrict types on the basis of members in general and not just constructors.

    
risposta data 23.04.2014 - 00:26
fonte
16

La decompilazione (come suggerito da Robert Harvey) ha prodotto quanto segue, per chiunque fosse interessato. Questo metodo:

static T GenericMake<T>()
    where T : new()
{
    return new T();
}

Apparentemente, una volta compilato, diventa questo:

private static T GenericMake<T>()
    where T : new()
{
    T t;
    T t1 = default(T);
    if (t1 == null)
    {
        t = Activator.CreateInstance<T>();
    }
    else
    {
        t1 = default(T);
        t = t1;
    }
    return t;
}
  • Se T è un tipo di valore, new() diventa default(T) .
  • Se T è un tipo di riferimento, new() funziona utilizzando la riflessione. Activator.CreateInstance() chiama internamente RuntimeType.CreateInstanceDefaultCtor() .

Quindi è così - internamente, i costruttori predefiniti sono davvero speciali per C # in relazione al CLR. Dare ad altri costruttori lo stesso trattamento sarebbe stato costoso, anche se ci sono alcuni casi d'uso validi per i vincoli più complicati nei generici.

    
risposta data 23.04.2014 - 01:56
fonte

Leggi altre domande sui tag