C # Crea nuovo T ()


159

Puoi vedere cosa sto cercando (ma non riesco) di fare con il seguente codice:

protected T GetObject()
{
    return new T();
}

Qualsiasi aiuto sarebbe molto apprezzato.

MODIFICARE:

Il contesto era il seguente. Stavo giocando con una classe di controller personalizzati da cui derivano tutti i controller, con metodi standardizzati. Quindi, nel contesto, dovevo creare una nuova istanza dell'oggetto del tipo di controller. Quindi al momento della scrittura, era qualcosa del tipo:

public class GenericController<T> : Controller
{
    ...

    protected T GetObject()
    {
        return (T)Activator.CreateInstance(ObjectType);
    }        

    public ActionResult Create()
    {
        var obj = GetObject()

        return View(obj);
    }

E così ho deciso che la riflessione era più semplice qui. Concordo sul fatto che, certamente data la dichiarazione iniziale della domanda, la risposta più appropriata da contrassegnare come corretta era quella che utilizzava il vincolo new (). L'ho risolto.


27
No, non vedo cosa stai cercando e non riesci a fare. Vedo un pezzo di codice che potrebbe far parte di un programma di lavoro, senza contesto, nessun messaggio di errore e nessuna spiegazione.
Ben Voigt,

17
Oh, lo odio quando viene selezionata la risposta sbagliata!
David Heffernan,

Risposte:


409

Dai un'occhiata al nuovo Vincolo

public class MyClass<T> where T : new()
{
    protected T GetObject()
    {
        return new T();
    }
}

Tpotrebbe essere una classe che non ha un costruttore predefinito: in questo caso new T()sarebbe un'istruzione non valida. Il new()vincolo dice che Tdeve avere un costruttore predefinito, che rende new T()legale.

È possibile applicare lo stesso vincolo a un metodo generico:

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

Se è necessario passare i parametri:

protected T GetObject(params object[] args)
{
    return (T)Activator.CreateInstance(typeof(T), args);
}

2
Grazie, amico - Sono felice di averlo imparato oggi. Dato il contesto del mio metodo, ho scelto la soluzione di riflessione. Saluti!
Hanshan,

8
@nulliusinverba - hmm ... sarebbe bello se mostrassi il contesto del tuo metodo nella domanda.
Alex Aza,

1
@nulliusinverba - non hai mostrato nella domanda che avevi bisogno di parametri.
Alex Aza,

1
@Alex - Quando ho letto la sua domanda ho pensato che non volesse parametri: S Votazione per te comunque :)
Phill

È possibile usare qualcosa come il nuovo vincolo (parametri)?
Louis Rhys,


29

Un altro modo è usare la riflessione:

protected T GetObject<T>(Type[] signature, object[] args)
{
    return (T)typeof(T).GetConstructor(signature).Invoke(args);
}

Grazie, amico - Sono andato con questa soluzione dato il contesto del metodo.
Hanshan,

22
Proprio come un FYI, questo può in alternativa essere scritto come Activator.CreateInstance (typeof (T), signature, args); vedere msdn.microsoft.com/en-us/library/4b0ww1we.aspx per maggiori dettagli.
Chris Baxter,

@Calgary Coder: a che serve una firma di tipo [], puoi semplicemente chiamare CreateInstance con i parametri direttamente, senza specificare esplicitamente la firma. In entrambi i casi otterresti MissingMethodException se non esiste un costruttore corrispondente.
Boris B.

4
Anche se questa è la risposta che funziona meglio per te, ovviamente non è la migliore per la comunità. Le persone che cercano questa domanda cercano davvero la risposta dal basso.
Trap

E cos'è esattamente quel contesto? Si prega di aggiungerlo alla domanda originale.
James,

18

Solo per il completamento, la soluzione migliore qui è spesso richiedere un argomento di funzione di fabbrica:

T GetObject<T>(Func<T> factory)
{  return factory(); }

e chiamalo in questo modo:

string s = GetObject(() => "result");

Puoi usarlo per richiedere o utilizzare i parametri disponibili, se necessario.


16

Il nuovo vincolo va bene, ma se hai bisogno che anche T sia un tipo di valore, usa questo:

protected T GetObject() {
    if (typeof(T).IsValueType || typeof(T) == typeof(string)) {
        return default(T);
    } else {
       return (T)Activator.CreateInstance(typeof(T));
    }
}

7

Dato che questo è etichettato C # 4. Con il framework open source ImpromptuIntereface utilizzerà il dlr per chiamare il costruttore, è significativamente più veloce di Activator quando il costruttore ha argomenti, e trascurabilmente più lento quando non lo è. Tuttavia, il vantaggio principale è che gestirà correttamente i costruttori con parametri opzionali C # 4.0, cosa che Activator non farà.

protected T GetObject(params object[] args)
{
    return (T)Impromptu.InvokeConstructor(typeof(T), args);
}

4

Per ottenere questo ho provato il seguente codice:

  protected T GetObject<T>()
    {
        T obj = default(T);
        obj =Activator.CreateInstance<T>();
        return obj ;
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.