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.


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

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

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.


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

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

4

Para obter isso, tentei o seguinte código:

  protected T GetObject<T>()
    {
        T obj = default(T);
        obj =Activator.CreateInstance<T>();
        return obj ;
    }
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.