Crie uma instância de uma classe a partir de uma sequência


217

Existe uma maneira de criar uma instância de uma classe com base no fato de eu saber o nome da classe em tempo de execução. Basicamente, eu teria o nome da classe em uma string.


Você parece ter descrito a solução que deseja implementar, mas não o problema que está tentando resolver. Talvez você esteja tentando fazer algo com extensibilidade. Nesse caso, sugiro que você verifique a Estrutura de extensibilidade gerenciada .
Jay Bazuzi 22/10/08

Respostas:


159

Dê uma olhada no método Activator.CreateInstance .


15
Relacionado com ótimos exemplos: stackoverflow.com/questions/493490/…
John S.

Também este post também será relevante, pois seu tipo precisa ser encontrado: stackoverflow.com/questions/1825147/…
Brad Parks


4
Por exemplo:var driver = (OpenQA.Selenium.IWebDriver)Activator.CreateInstance("WebDriver", "OpenQA.Selenium.Firefox.FirefoxDriver").Unwrap();
Endy Tjahjono 04/10

2
Nota importante aqui: .Unwrap () para passar pelo identificador de comunicação remota, para que você possa realmente executar as transmissões. @Endy - Thanks
Roger Willcocks

77

É bem simples. Suponha que seu nome de classe seja Care o namespace seja Vehicles, depois passe o parâmetro como o Vehicles.Carque retorna o objeto do tipo Car. Assim, você pode criar qualquer instância de qualquer classe dinamicamente.

public object GetInstance(string strFullyQualifiedName)
{         
     Type t = Type.GetType(strFullyQualifiedName); 
     return  Activator.CreateInstance(t);         
}

Se o seu nome completo (ou seja, Vehicles.Carneste caso) estiver em outra montagem, o valor Type.GetTypeserá nulo. Nesses casos, você percorre todas as montagens e encontra o Type. Para isso você pode usar o código abaixo

public object GetInstance(string strFullyQualifiedName)
{
     Type type = Type.GetType(strFullyQualifiedName);
     if (type != null)
         return Activator.CreateInstance(type);
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
     {
         type = asm.GetType(strFullyQualifiedName);
         if (type != null)
             return Activator.CreateInstance(type);
     }
     return null;
 }

Agora, se você quiser chamar um construtor parametrizado, faça o seguinte

Activator.CreateInstance(t,17); // Incase you are calling a constructor of int type

ao invés de

Activator.CreateInstance(t);

Como usá-lo sem vazamento e como fazer o elenco a partir da string especificada ?
TaW

1
@TaW - para usar uma instância de classe, você precisará ter algum conhecimento do que vai fazer - caso contrário, não poderá usá-lo. O caso de uso mais comum para isso seria converter para alguma interface que fornece um contrato predefinido. (Isso é válido a menos que você esteja usando o dynamiccódigo - consulte stackoverflow.com/a/2690661/904521 )
Tomer Cagan

1
Não codifique o tipo da variável em seu nome., Por exemplo: não há necessidade de prefixar strFullyQualifiedNamecom str, fullyQualifiedNamefará o trabalho.
Mehdi Dehghani

A palavra str- chave é usada como parte da convenção de nomenclatura para variáveis. Certas organizações e projetos insistem em seguir isso, por isso eu usei. Se você tivesse trabalhado em certas organizações / projetos, saberá disso. Como você disse sem, strtambém fará o trabalho :) @MehdiDehghani #
Sarath Avanavu

1
Eu sei que não há necessidade de trabalhar em nenhuma organização para saber sobre convenções de nomenclatura, porém, essa convenção conhecida como notação húngara e é uma das convenções de nomenclatura ruins e obsoletas por aí. especialmente para C #
Mehdi Dehghani

55

Eu usei esse método com sucesso:

System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(string className)

Você precisará converter o objeto retornado para o tipo de objeto desejado.


9
Estou tentando imaginar um cenário em que criar o objeto por meio do nome da classe e, em seguida, convertê-lo como esse tipo faria algum sentido.
MusiGenesis 21/10/08

13
Eu vejo o que você quer dizer. Parece redundante. Se você conhece o nome da classe, por que precisa da sequência dinâmica? Uma situação pode ser que você esteja convertendo para uma classe base e a sequência represente descendentes dessa classe base.
Ray Li

4
Se a classe base for conhecida, você poderá usar a classe base ou uma interface como argumento para passar descendentes sem reflexão.
Garet Claborn

3
Cenário útil: você só precisa das interfaces de serialização ou de qualquer outra interface bastante comum. Você não vai lançá-lo para a classe, mas pelo menos a algo mais do que um objeto
Harald Coppoolse

2
Como fazer o elenco da string especificada ??
TAW

23

Provavelmente minha pergunta deveria ter sido mais específica. Na verdade, eu conheço uma classe base para a string, então resolvi:

ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

A classe Activator.CreateInstance possui vários métodos para obter a mesma coisa de maneiras diferentes. Eu poderia lançá-lo em um objeto, mas o acima é mais útil para a minha situação.


4
Em vez de responder na seção de perguntas, sugiro que você edite sua pergunta e observe as alterações. Você obterá mais / melhores respostas para fazê-lo.
23680 Jason Jackson

Obrigado por postar a linha de código específica que funcionou para você. A ordenação de todas as sobrecargas de CreateInstance e diferentes maneiras de gerar tipos estava demorando muito tempo, o que você me salvou.
Ethel Evans

4

Eu sei que estou atrasado para o jogo ... mas a solução que você está procurando pode ser a combinação dos itens acima e usar uma interface para definir os aspectos acessíveis ao público dos seus objetos.

Então, se todas as suas classes que seriam geradas dessa maneira implementarem essa interface, você poderá apenas converter como o tipo de interface e trabalhar com o objeto resultante.


4

Para criar uma instância de uma classe a partir de outro projeto na solução, você pode obter o assembly indicado pelo nome de qualquer classe (por exemplo BaseEntity) e criar uma nova instância:

  var newClass = System.Reflection.Assembly.GetAssembly(typeof(BaseEntity)).CreateInstance("MyProject.Entities.User");

3

Por exemplo, se você armazenar valores de vários tipos em um campo do banco de dados (armazenado como string) e tiver outro campo com o nome do tipo (por exemplo, String, bool, int, MyClass), a partir desses dados do campo, você poderá, possivelmente, crie uma classe de qualquer tipo usando o código acima e preencha-o com o valor do primeiro campo. Obviamente, isso depende do tipo que você está armazenando e de um método para analisar as seqüências de caracteres no tipo correto. Eu usei isso muitas vezes para armazenar configurações de preferência do usuário em um banco de dados.


-11
ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

por que você quer escrever um código como este? Se você tiver uma classe 'ReportClass' disponível, instancie-a diretamente, como mostrado abaixo.

ReportClass report = new ReportClass();

O código ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));é usado quando você não possui a classe necessária disponível, mas deseja instanciar e / ou chamar um método dinamicamente.

Quero dizer, é útil quando você conhece o assembly, mas ao escrever o código, você não tem a classe ReportClassdisponível.

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.