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.

Hanshan
quelle
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);
}
Alex Aza
quelle
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);
}
Sean Thoman
quelle
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.

Joel Coehoorn
quelle
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));
    }
}
Lukas Cenovsky
quelle
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);
}
jbtule
quelle
4

Um dies zu bekommen, habe ich folgenden Code versucht:

  protected T GetObject<T>()
    {
        T obj = default(T);
        obj =Activator.CreateInstance<T>();
        return obj ;
    }
UJS
quelle