C # Criar novo T ()

159

Você pode ver o que estou tentando (mas falhando) com o seguinte código:

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

Qualquer ajuda seria muito apreciada.

EDITAR:

O contexto foi o seguinte. Eu estava brincando com uma classe de controlador personalizada para a qual todos os controladores derivam, com métodos padronizados. Portanto, no contexto, eu precisava criar uma nova instância do objeto do tipo de controlador. Então, no momento da escrita, era algo como:

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

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

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

        return View(obj);
    }

E então eu decidi que a reflexão era mais fácil aqui. Concordo que, certamente, dada a afirmação inicial da pergunta, a resposta mais apropriada para marcar como correta foi a que estava usando a nova restrição (). Eu consertei isso.

Hanshan
fonte
27
Não, não vejo o que você está tentando e deixando de fazer. Vejo um pedaço de código que poderia fazer parte de um programa de trabalho, sem contexto, sem mensagem de erro e sem explicação.
Ben Voigt
17
Ah, eu odeio quando a resposta errada é selecionada!
David Heffernan

Respostas:

409

Dê uma olhada no novo Constraint

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

Tpoderia ser uma classe que não possui um construtor padrão: nesse caso, new T()seria uma instrução inválida. A new()restrição diz que Tdeve ter um construtor padrão, o que torna new T()legal.

Você pode aplicar a mesma restrição a um método genérico:

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

Se você precisar passar parâmetros:

protected T GetObject(params object[] args)
{
    return (T)Activator.CreateInstance(typeof(T), args);
}
Alex Aza
fonte
2
Obrigado, companheiro - estou feliz por ter aprendido isso hoje. Dado o contexto do meu método, busquei a solução de reflexão. Felicidades!
Hanshan
8
@ nulliusinverba - hmm ... seria bom se você mostrasse o contexto do seu método na pergunta.
Alex Aza
1
@ nulliusinverba - você não mostrou na pergunta que precisava de parâmetros.
Alex Aza
1
@Alex - Quando li a sua pergunta eu assumi que ele não queria parâmetros: S Up-voto para você no entanto :)
Phill
É possível usar algo como nova restrição (parâmetros)?
Louis Rhys
29

Outra maneira é usar a reflexão:

protected T GetObject<T>(Type[] signature, object[] args)
{
    return (T)typeof(T).GetConstructor(signature).Invoke(args);
}
Sean Thoman
fonte
Obrigado, companheiro - eu fui com esta solução, dado o contexto do método.
Hanshan
22
Assim como um FYI, isso também pode ser escrito como Activator.CreateInstance (typeof (T), signature, args); consulte msdn.microsoft.com/en-us/library/4b0ww1we.aspx para obter mais detalhes.
Chris Baxter
@ Calgary Coder: Para que serve uma assinatura de tipo [], você pode simplesmente chamar CreateInstance com parâmetros diretamente, sem especificar explicitamente a assinatura. Nos dois casos, você obteria MissingMethodException se um construtor correspondente não existir.
Boris B.
4
Mesmo que essa seja a resposta que melhor funcione para você, obviamente não é a melhor para a comunidade. As pessoas que procuram esta pergunta estão procurando a resposta abaixo, na verdade.
Armadilha
E o que exatamente é esse contexto? Por favor, adicione-o à pergunta original.
James
18

Apenas para conclusão, a melhor solução aqui é geralmente exigir um argumento de função de fábrica:

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

e chame de algo assim:

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

Você pode usar isso para exigir ou usar os parâmetros disponíveis, se necessário.

Joel Coehoorn
fonte
16

A nova restrição é boa, mas se você também precisar de um tipo de valor T, use este:

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

Como esse código está marcado como C # 4. Com a estrutura de código-fonte aberto ImpromptuIntereface, ele usará o dlr para chamar o construtor. É significativamente mais rápido que o Activator quando o construtor tem argumentos, e notavelmente mais lento quando não. No entanto, a principal vantagem é que ele manipulará os construtores com parâmetros opcionais do C # 4.0 corretamente, algo que o Activator não fará.

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

Para obter isso, tentei o seguinte código:

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