C # Crear nueva T ()

159

Puedes ver lo que intento (pero no puedo) hacer con el siguiente código:

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

Cualquier ayuda sería muy apreciada.

EDITAR:

El contexto fue el siguiente. Estaba jugando con una clase de controlador personalizado para todos los controladores, con métodos estandarizados. Entonces, en contexto, necesitaba crear una nueva instancia del objeto del tipo de controlador. Entonces, al momento de escribir, era algo así como:

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

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

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

        return View(obj);
    }

Entonces decidí que la reflexión era más fácil aquí. Estoy de acuerdo en que, ciertamente dada la declaración inicial de la pregunta, la respuesta más apropiada para marcar como correcta fue la que usa la restricción new (). He arreglado eso.

Hanshan
fuente
27
No, no veo lo que estás intentando y no puedes hacer. Veo un fragmento de código que podría ser parte de un programa de trabajo, sin contexto, sin mensaje de error y sin explicación.
Ben Voigt
17
Aw, ¡odio cuando se selecciona la respuesta incorrecta!
David Heffernan

Respuestas:

409

Echa un vistazo a la nueva restricción

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

Tpodría ser una clase que no tiene un constructor predeterminado: en este caso new T()sería una declaración no válida. La new()restricción dice que Tdebe tener un constructor predeterminado, lo que lo hace new T()legal.

Puede aplicar la misma restricción a un método genérico:

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

Si necesita pasar parámetros:

protected T GetObject(params object[] args)
{
    return (T)Activator.CreateInstance(typeof(T), args);
}
Alex Aza
fuente
2
Gracias, amigo. Me alegro de haber aprendido esto hoy. Dado el contexto de mi método, he optado por la solución de reflexión. ¡Salud!
Hanshan
8
@nulliusinverba - hmm ... sería bueno que mostraras el contexto de tu método en la pregunta.
Alex Aza
1
@nulliusinverba: en la pregunta no mostraste que necesitabas parámetros.
Alex Aza
1
@Alex - Cuando leí su pregunta supuse que no quería parámetros: S Vota por ti sin embargo :)
Phill
¿Es posible usar algo como una nueva restricción (parámetros)?
Louis Rhys
29

Otra forma es usar la reflexión:

protected T GetObject<T>(Type[] signature, object[] args)
{
    return (T)typeof(T).GetConstructor(signature).Invoke(args);
}
Sean Thoman
fuente
Gracias, amigo. Fui con esta solución dado el contexto del método.
Hanshan
22
Al igual que para su información, esto puede escribirse alternativamente como Activator.CreateInstance (typeof (T), signature, args); Consulte msdn.microsoft.com/en-us/library/4b0ww1we.aspx para obtener más detalles.
Chris Baxter
@Calgary Coder: ¿De qué sirve una firma de tipo [], puede llamar a CreateInstance con parámetros directamente, sin especificar explícitamente la firma. En ambos casos, obtendrá MissingMethodException si no existe un constructor coincidente.
Boris B.
44
Incluso si esta es la respuesta que funciona mejor para usted, obviamente no es la mejor para la comunidad. Las personas que buscan esta pregunta buscan la respuesta desde abajo, de verdad.
Trampa
¿Y cuál es exactamente ese contexto? Por favor agrégalo a la pregunta original.
James
18

Solo para completar, la mejor solución aquí es a menudo requerir un argumento de función de fábrica:

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

y llámalo así:

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

Puede usar eso para requerir o hacer uso de los parámetros disponibles, si es necesario.

Joel Coehoorn
fuente
16

La nueva restricción está bien, pero si necesita que T sea también un tipo de valor, use esto:

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

Dado que esto está etiquetado como C # 4. Con el marco de referencia abierto ImpromptuIntereface , usará el dlr para llamar al constructor, es significativamente más rápido que Activator cuando su constructor tiene argumentos, y mucho más lento cuando no lo tiene. Sin embargo, la principal ventaja es que manejará los constructores con parámetros opcionales de C # 4.0 correctamente, algo que Activator no hará.

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

Para obtener esto probé el siguiente código:

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