C # Utwórz nowe T ()

159

Możesz zobaczyć, co próbuję (ale bezskutecznie) zrobić z następującym kodem:

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

Każda pomoc byłaby bardzo mile widziana.

EDYTOWAĆ:

Kontekst był następujący. Bawiłem się niestandardową klasą kontrolera, z której miały pochodzić wszystkie kontrolery, przy użyciu standardowych metod. W kontekście musiałem więc stworzyć nową instancję obiektu typu kontroler. Więc w czasie pisania było to coś takiego:

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

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

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

        return View(obj);
    }

Postanowiłem więc, że tu najłatwiej będzie nam zadbać o refleksję. Zgadzam się, że z pewnością biorąc pod uwagę początkowe stwierdzenie pytania, najwłaściwszą odpowiedzią do oznaczenia jako poprawną była ta, w której zastosowano nowe () ograniczenie. Naprawiłem to.

Hanshan
źródło
27
Nie, nie rozumiem, co próbujesz, a czego się nie udaje. Widzę fragment kodu, który mógłby być częścią działającego programu, bez kontekstu, bez komunikatu o błędzie i bez wyjaśnienia.
Ben Voigt
17
Aw, nienawidzę, gdy wybrano złą odpowiedź!
David Heffernan

Odpowiedzi:

409

Spójrz na nowe ograniczenie

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

Tmogłaby być klasą, która nie ma domyślnego konstruktora: w tym przypadku new T()byłaby to nieprawidłowa instrukcja. new()Ograniczenie mówi, że Tmusi mieć konstruktora domyślnego, co czyni new T()prawa.

Możesz zastosować to samo ograniczenie do metody ogólnej:

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

Jeśli potrzebujesz przekazać parametry:

protected T GetObject(params object[] args)
{
    return (T)Activator.CreateInstance(typeof(T), args);
}
Alex Aza
źródło
2
Dzięki kolego - cieszę się, że się tego dzisiaj dowiedziałem. Biorąc pod uwagę kontekst mojej metody, wybrałem rozwiązanie refleksyjne. Twoje zdrowie!
Hanshan
8
@nulliusinverba - hmm ... byłoby miło, gdybyś w pytaniu pokazał kontekst swojej metody.
Alex Aza
1
@nulliusinverba - nie pokazałeś w pytaniu, że potrzebujesz parametrów.
Alex Aza
1
@Alex - Kiedy przeczytałem jego pytanie, założyłem, że nie chce parametrów: S Głosuj pozytywnie na ciebie :)
Phill
Czy można użyć czegoś takiego jak nowe (parametry) ograniczenia?
Louis Rhys,
29

Innym sposobem jest użycie refleksji:

protected T GetObject<T>(Type[] signature, object[] args)
{
    return (T)typeof(T).GetConstructor(signature).Invoke(args);
}
Sean Thoman
źródło
Dzięki kolego - wybrałem to rozwiązanie biorąc pod uwagę kontekst metody.
Hanshan
22
Podobnie jak FYI, można to alternatywnie zapisać jako Activator.CreateInstance (typeof (T), signature, args); Więcej szczegółów można znaleźć na stronie msdn.microsoft.com/en-us/library/4b0ww1we.aspx .
Chris Baxter
@Calgary Coder: Jaki jest pożytek z podpisu typu []? Możesz po prostu wywołać CreateInstance bezpośrednio z parametrami, bez jawnego określania podpisu. W obu przypadkach otrzymasz MissingMethodException, jeśli pasujący konstruktor nie istnieje.
Boris B.
4
Nawet jeśli jest to odpowiedź, która najbardziej Ci odpowiada, to oczywiście nie jest najlepsza dla społeczności. Osoby szukające tego pytania naprawdę szukają odpowiedzi od dołu.
Trap
A czym właściwie jest ten kontekst? Dodaj go do pierwotnego pytania.
James
18

Aby zakończyć, najlepszym rozwiązaniem jest często wymaganie argumentu funkcji fabrycznej:

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

i nazwij to mniej więcej tak:

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

W razie potrzeby można tego użyć, aby wymagać lub skorzystać z dostępnych parametrów.

Joel Coehoorn
źródło
16

Nowy ograniczeniem jest w porządku, ale jeśli trzeba T jest typ wartości też użyć tego:

protected T GetObject() {
    if (typeof(T).IsValueType || typeof(T) == typeof(string)) {
        return default(T);
    } else {
       return (T)Activator.CreateInstance(typeof(T));
    }
}
Lukas Cenovsky
źródło
7

Ponieważ jest oznaczony jako C # 4. Z otwartym środowiskiem źródłowym ImpromptuIntereface użyje dlr do wywołania konstruktora, jest to znacznie szybsze niż Activator, gdy konstruktor ma argumenty, i pomijalnie wolniejsze, gdy ich nie ma. Jednak główną zaletą jest to, że poprawnie obsłuży konstruktory z opcjonalnymi parametrami C # 4.0, czego nie zrobi Activator.

protected T GetObject(params object[] args)
{
    return (T)Impromptu.InvokeConstructor(typeof(T), args);
}
jbtule
źródło
4

Aby to uzyskać, wypróbowałem następujący kod:

  protected T GetObject<T>()
    {
        T obj = default(T);
        obj =Activator.CreateInstance<T>();
        return obj ;
    }
UJS
źródło