C # Neues T erstellen ()


158

Sie können sehen, was ich mit dem folgenden Code versuche (aber nicht schaffe):

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

Jede Hilfe wäre sehr dankbar.

BEARBEITEN:

Der Kontext war wie folgt. Ich habe mit einer benutzerdefinierten Controller-Klasse herumgespielt, von der alle Controller mit standardisierten Methoden abgeleitet werden können. Im Kontext musste ich also eine neue Instanz des Objekts vom Controllertyp erstellen. Zum Zeitpunkt des Schreibens war es so etwas wie:

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

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

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

        return View(obj);
    }

Und so entschied ich, dass Reflexion hier am einfachsten ist. Ich bin damit einverstanden, dass angesichts der ursprünglichen Aussage der Frage die am besten geeignete Antwort, um sie als richtig zu markieren, diejenige war, die die neue () - Einschränkung verwendet. Ich habe das behoben.


27
Nein, ich verstehe nicht, was Sie versuchen und was nicht. Ich sehe einen Code, der Teil eines Arbeitsprogramms sein könnte, ohne Kontext, ohne Fehlermeldung und ohne Erklärung.
Ben Voigt

17
Oh, ich hasse es, wenn die falsche Antwort ausgewählt wird!
David Heffernan

Antworten:


409

Schauen Sie sich die neue Einschränkung an

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

Tkönnte eine Klasse sein, die keinen Standardkonstruktor hat: In diesem Fall new T()wäre dies eine ungültige Anweisung. Die new()Einschränkung besagt, Tdass ein Standardkonstruktor vorhanden sein muss, der new T()legal ist.

Sie können dieselbe Einschränkung auf eine generische Methode anwenden:

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

Wenn Sie Parameter übergeben müssen:

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

2
Danke, Kumpel - ich bin froh, das heute gelernt zu haben. Angesichts des Kontextes meiner Methode habe ich mich für die Reflexionslösung entschieden. Prost!
Hanshan

8
@nulliusinverba - hmm ... es wäre schön, wenn Sie den Kontext Ihrer Methode in der Frage zeigen würden.
Alex Aza

1
@nulliusinverba - Sie haben in der Frage nicht gezeigt, dass Sie Parameter benötigen.
Alex Aza

1
@ Alex - Als ich seine Frage las, nahm ich an, dass er keine Parameter wollte: S Up-Vote für Sie jedoch :)
Phill

Ist es möglich, so etwas wie eine neue (Parameter-) Einschränkung zu verwenden?
Louis Rhys


29

Eine andere Möglichkeit ist die Verwendung von Reflexion:

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

Danke, Kumpel - ich habe mich angesichts des Kontextes der Methode für diese Lösung entschieden.
Hanshan

22
Genau wie zu Ihrer Information kann dies alternativ als Activator.CreateInstance (typeof (T), Signatur, Argumente) geschrieben werden. Weitere Informationen finden Sie unter msdn.microsoft.com/en-us/library/4b0ww1we.aspx .
Chris Baxter

@Calgary Coder: Was nützt eine Signatur vom Typ []? Sie können CreateInstance einfach direkt mit Parametern aufrufen, ohne die Signatur explizit anzugeben. In beiden Fällen erhalten Sie MissingMethodException, wenn kein übereinstimmender Konstruktor vorhanden ist.
Boris B.

4
Auch wenn dies die Antwort ist, die für Sie am besten funktioniert, ist sie offensichtlich nicht die beste für die Community. Leute, die nach dieser Frage suchen, suchen wirklich nach der Antwort von unten.
Falle

Und was genau ist das für ein Kontext? Bitte fügen Sie es der ursprünglichen Frage hinzu.
James

18

Nur zur Vervollständigung besteht die beste Lösung häufig darin, ein Factory-Funktionsargument zu benötigen:

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

und nenne es so etwas:

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

Sie können dies verwenden, um verfügbare Parameter bei Bedarf zu benötigen oder zu nutzen.


16

Die neue Einschränkung ist in Ordnung, aber wenn Sie T auch als Werttyp benötigen, verwenden Sie Folgendes:

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

7

Da dies mit C # 4 gekennzeichnet ist, wird mit dem Open-Sourece-Framework ImpromptuIntereface der Konstruktor mithilfe der DLR aufgerufen. Es ist erheblich schneller als Activator, wenn Ihr Konstruktor Argumente hat, und vernachlässigbar langsamer, wenn dies nicht der Fall ist. Der Hauptvorteil besteht jedoch darin, dass Konstruktoren mit optionalen C # 4.0-Parametern korrekt behandelt werden, was Activator nicht kann.

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

4

Um dies zu bekommen, habe ich folgenden Code versucht:

  protected T GetObject<T>()
    {
        T obj = default(T);
        obj =Activator.CreateInstance<T>();
        return obj ;
    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.