Estou tentando criar um novo objeto do tipo T através de seu construtor ao adicionar à lista.
Estou recebendo um erro de compilação: A mensagem de erro é:
'T': não é possível fornecer argumentos ao criar uma instância de uma variável
Mas minhas classes têm um argumento construtor! Como posso fazer isso funcionar?
public static string GetAllItems<T>(...) where T : new()
{
...
List<T> tabListItems = new List<T>();
foreach (ListItem listItem in listCollection)
{
tabListItems.Add(new T(listItem)); // error here.
}
...
}
c#
.net
generics
new-operator
LIBRA.
fonte
fonte
Respostas:
Para criar uma instância de um tipo genérico em uma função, você deve restringi-la com o sinalizador "novo".
No entanto, isso só funcionará quando você desejar chamar o construtor que não possui parâmetros. Não é o caso aqui. Em vez disso, você precisará fornecer outro parâmetro que permita a criação de objeto com base em parâmetros. O mais fácil é uma função.
Você pode então chamar assim
fonte
T result = thunk == null ? new T() : thunk();
O benefício disso para mim é consolidar a lógica daT
criação em um só lugar, em vez de criar algumas vezesT
dentro e outras fora do método.no .Net 3.5 e depois que você pudesse usar a classe ativator:
fonte
Activator.CreateInstance
isso, parecerá que seu construtor não foi usado e alguém poderá tentar "limpar" e excluí-lo (para causar um erro de execução em algum tempo aleatório no futuro). Você pode considerar adicionar uma função fictícia onde você usa esse construtor apenas para obter um erro de compilação se tentar excluí-lo.Como ninguém se preocupou em postar a resposta 'Reflexão' (que eu pessoalmente acho que é a melhor resposta), aqui vai:
Editar: esta resposta foi descontinuada devido ao Activator.CreateInstance do .NET 3.5, no entanto, ainda é útil em versões mais antigas do .NET.
fonte
Inicializador de objeto
Se o seu construtor com o parâmetro não estiver fazendo nada além de definir uma propriedade, você pode fazer isso no C # 3 ou melhor usando um inicializador de objeto em vez de chamar um construtor (o que é impossível, como já foi mencionado):
Usando isso, você sempre pode colocar qualquer lógica de construtor no construtor padrão (vazio) também.
Activator.CreateInstance ()
Como alternativa, você pode chamar Activator.CreateInstance () assim:
Observe que Activator.CreateInstance pode ter alguma sobrecarga de desempenho que você pode evitar se a velocidade de execução for uma prioridade e outra opção puder ser mantida por você.
fonte
T
proteção de seus invariantes (dado queT
tem> 0 dependências ou valores obrigatórios, agora você pode criar instânciasT
que estão em um estado inválido / inutilizávelT
.Pergunta muito antiga, mas nova resposta ;-)
A versão ExpressionTree : (acho que a solução mais rápida e mais limpa)
Como Welly Tambunan disse, "também podemos usar a árvore de expressão para construir o objeto"
Isso irá gerar um 'construtor' (função) para o tipo / parâmetros fornecidos. Ele retorna um delegado e aceita os tipos de parâmetro como uma matriz de objetos.
Aqui está:
Exemplo MyClass:
Uso:
Outro exemplo: passando os tipos como uma matriz
DebugView of Expression
Isso é equivalente ao código que é gerado:
Pequena desvantagem
Todos os parâmetros de tipos de valor são colocados em caixa quando são passados como uma matriz de objetos.
Teste de desempenho simples:
Resultados:
Usar
Expressions
é +/- 8 vezes mais rápido que InvocarConstructorInfo
e +/- 20 vezes mais rápido que usar oActivator
fonte
var myConstructor = CreateConstructor(typeof(MyClass<int>), typeof(int));
isso está funcionando bem. Eu não sei.Isso não vai funcionar na sua situação. Você só pode especificar a restrição de que ele tenha um construtor vazio:
O que você pode fazer é usar a injeção de propriedade, definindo esta interface:
Então você pode alterar seu método para ser o seguinte:
A outra alternativa é o
Func
método descrito por JaredPar.fonte
Você precisa adicionar onde T: new () para informar ao compilador que T é garantido para fornecer um construtor padrão.
fonte
Se você deseja simplesmente inicializar um campo ou propriedade membro com o parâmetro construtor, em C #> = 3, você pode fazer isso muito mais facilmente:
É a mesma coisa que Garry Shutler disse, mas eu gostaria de colocar uma nota adicional.
É claro que você pode usar um truque de propriedade para fazer mais coisas do que apenas definir um valor de campo. Uma propriedade "set ()" pode acionar qualquer processamento necessário para configurar seus campos relacionados e qualquer outra necessidade do próprio objeto, incluindo uma verificação para verificar se uma inicialização completa deve ocorrer antes do objeto ser usado, simulando uma construção completa ( sim, é uma solução feia, mas supera a nova limitação de M $ ().
Não posso ter certeza se é um buraco planejado ou um efeito colateral acidental, mas funciona.
É muito engraçado como as pessoas com esclerose múltipla adicionam novos recursos ao idioma e parecem não fazer uma análise completa dos efeitos colaterais. A coisa toda genérica é uma boa evidência disso ...
fonte
Descobri que estava recebendo um erro "não é possível fornecer argumentos ao criar uma instância do tipo parâmetro T", então eu precisava fazer isso:
fonte
Se você tiver acesso à classe que usará, poderá usar esta abordagem que eu usei.
Crie uma interface que tenha um criador alternativo:
Faça suas aulas com um criador vazio e implemente este método:
Agora use seus métodos genéricos:
Se você não tiver acesso, agrupe a classe de destino:
fonte
Isso é meio bobo, e quando digo meio bobo, posso significar revoltante, mas supondo que você possa fornecer seu tipo parametrizado com um construtor vazio, então:
Permite efetivamente construir um objeto a partir de um tipo parametrizado com um argumento. Neste caso, estou assumindo que o construtor que eu quero tem um único argumento do tipo
object
. Criamos uma instância fictícia de T usando o construtor vazio de restrição permitido e depois usamos a reflexão para obter um de seus outros construtores.fonte
Às vezes, uso uma abordagem semelhante às respostas usando injeção de propriedade, mas mantém o código mais limpo. Em vez de ter uma classe / interface base com um conjunto de propriedades, ele contém apenas um método (virtual) Initialize () - que atua como um "construtor pobre". Em seguida, você pode permitir que cada classe lide com sua própria inicialização, como faria um construtor, o que também adiciona uma maneira conveniente de lidar com cadeias de herança.
Se muitas vezes me encontro em situações em que quero que cada classe na cadeia inicialize suas propriedades exclusivas e chame o método Initialize () dos pais, que por sua vez inicializa as propriedades exclusivas dos pais e assim por diante. Isso é especialmente útil quando se tem classes diferentes, mas com uma hierarquia semelhante, por exemplo, objetos de negócios que são mapeados para / de DTO: s.
Exemplo que usa um dicionário comum para inicialização:
fonte
Se tudo o que você precisa é de conversão de ListItem para seu tipo T, você pode implementar essa conversão na classe T como operador de conversão.
fonte
Eu acredito que você precisa restringir T com uma instrução where para permitir apenas objetos com um novo construtor.
Agora, ele aceita qualquer coisa, incluindo objetos sem ele.
fonte