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.


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);
}

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);
}

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.


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));
    }
}

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);
}

4

Para obtener esto probé el siguiente código:

  protected T GetObject<T>()
    {
        T obj = default(T);
        obj =Activator.CreateInstance<T>();
        return obj ;
    }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.