Posso carregar um assembly .NET em tempo de execução e instanciar um tipo que sabe apenas o nome?


178

É possível instanciar um objeto em tempo de execução se eu tiver apenas o nome da DLL e o nome da classe, sem adicionar uma referência ao assembly no projeto? A classe implementa uma interface, portanto, quando eu instanciar a classe, a converteremos na interface.

Nome da montagem:

library.dll

Digite o nome:

Company.Project.Classname


Edição: Eu não tenho o caminho absoluto da DLL, por Assembly.LoadFileisso não vai funcionar. A DLL pode estar na raiz do aplicativo, system32 ou mesmo carregada no GAC.

Respostas:


221

Sim. Você precisa usar Assembly.LoadFrompara carregar a montagem na memória e, em seguida, Activator.CreateInstancecriar uma instância do seu tipo preferido. Você precisará procurar o tipo primeiro usando reflexão. Aqui está um exemplo simples:

Assembly assembly = Assembly.LoadFrom("MyNice.dll");

Type type = assembly.GetType("MyType");

object instanceOfMyType = Activator.CreateInstance(type);

Atualizar

Quando você tem o nome do arquivo de montagem e o nome do tipo, pode Activator.CreateInstance(assemblyName, typeName)solicitar à resolução de tipo .NET que resolva isso em um tipo. Você pode agrupar isso com uma tentativa / captura, para que, se falhar, você pode executar uma pesquisa de diretórios nos quais pode armazenar especificamente assemblies adicionais que, de outra forma, não seriam pesquisados. Isso usaria o método anterior nesse ponto.


2
Eu não tenho o caminho absoluto da dll, então assemlby.LoadFile ect. não vai funcionar, outras idéias?
MegaByte

@rp sempre dispostos a ajudar (e só um ano de atraso em dizer isso!)
Jeff Yates

2
@MegaByte: LoadFrom é diferente de LoadFile. Ele resolverá suas dependências e o nome da DLL de caminhos conhecidos (GAC, diretório exe etc.). Consulte o MSDN para obter mais informações.
Jeff Yates

1
Só mais uma coisa ... (eu novamente) Hum, você não pode simplesmente ter "MyType" como o nome do tipo, ele deve ser seguido por NAMESPACE. Portanto, isso seria mais preciso:Type type = assembly.GetType("MyNamespace"+"."+"MyType");
Cipi 14/02

1
@ Cipi: Tecnicamente, um tipo é o nome completo no namespace (o conceito de namespace é uma conveniência de idioma). Você pode ter um tipo sem espaço para nome no CLR - eu estava apenas fornecendo um exemplo excessivamente simplificado.
Jeff Yates

36

Considere as limitações dos diferentes Load*métodos. Dos documentos do MSDN ...

O LoadFile não carrega arquivos no contexto LoadFrom e não resolve dependências usando o caminho de carregamento, como o método LoadFrom.

Mais informações sobre Contextos de carregamento podem ser encontradas nos LoadFromdocumentos.


19

Activator.CreateInstance deve funcionar.

IFace object = (IFace)Activator.CreateInstance( "AssemblyName",
                                                "TypeName" )
                               .Unwrap();

Nota: O nome do tipo deve ser o tipo completo.

Exemplo:

var aray = (IList)Activator.CreateInstance("mscorlib","System.Collections.ArrayList").Unwrap();
aray.Add(10);

foreach (object obj in aray)
{
    Console.WriteLine(obj);
}

1
Apenas uma observação: TypeNamedeve ser totalmente qualificado. Eu tive que chamar isso assim: Activator.CreateInstance("MyAssembly","MyAssembly.TypeName") E isso retorna um ObjectHandle. Para começar a sua interface que você precisa fazerObjectHandle.UnWrap()
Anthony Sottile

7

Encontrei essa pergunta e algumas respostas muito úteis, porém tive problemas de caminho, portanto, essa resposta abrangeria o carregamento da biblioteca encontrando o caminho do diretório bin.

Primeira solução:

string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFrom(assemblyPath);
Type T = assembly.GetType("Company.Project.Classname");
Company.Project.Classname instance = (Company.Project.Classname) Activator.CreateInstance(T);

Segunda solução

string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFile(assemblyPath);
(Company.Project.Classname) instance = (Company.Project.Classname) assembly.CreateInstance("Company.Project.Classname");

Você pode usar o mesmo princípio para interfaces (você criaria uma classe, mas converterá em interface), como:

(Company.Project.Interfacename) instance = (Company.Project.Interfacename) assembly.CreateInstance("Company.Project.Classname");

Este exemplo é para aplicativo Web, mas similar pode ser usado para aplicativo Desktop, apenas o caminho é resolvido de maneira diferente, por exemplo

Path.GetDirectoryName(Application.ExecutablePath)

5

É fácil.

Exemplo do MSDN:

public static void Main()
{
    // Use the file name to load the assembly into the current
    // application domain.
    Assembly a = Assembly.Load("example");
    // Get the type to use.
    Type myType = a.GetType("Example");
    // Get the method to call.
    MethodInfo myMethod = myType.GetMethod("MethodA");
    // Create an instance.
    object obj = Activator.CreateInstance(myType);
    // Execute the method.
    myMethod.Invoke(obj, null);
}

Aqui está um link de referência

https://msdn.microsoft.com/en-us/library/25y1ya39.aspx


Essa é uma maneira horrível de oferecer suporte ao carregamento dinâmico de código. A MS sempre gostou de nos forçar a entrar em muitos detalhes.
Clearer

3

A partir do Framework v4.5, você pode usar o Activator.CreateInstanceFrom () para instanciar facilmente as classes nos assemblies. O exemplo a seguir mostra como usá-lo e como chamar um método passando parâmetros e obtendo valor de retorno.

    // Assuming moduleFileName contains full or valid relative path to assembly    
    var moduleInstance = Activator.CreateInstanceFrom(moduleFileName, "MyNamespace.MyClass");
    MethodInfo mi = moduleInstance.Unwrap().GetType().GetMethod("MyMethod");
    // Assuming the method returns a boolean and accepts a single string parameter
    bool rc = Convert.ToBoolean(mi.Invoke(moduleInstance.Unwrap(), new object[] { "MyParamValue" } ));


2
((ISomeInterface)Activator.CreateInstance(Assembly.LoadFile("somePath").GetTypes()[0])).SomeInterfaceMethod();

2

Você pode carregar uma montagem usando os métodos * Assembly.Load **. Usando Activator.CreateInstance, você pode criar novas instâncias do tipo desejado. Lembre-se de que você deve usar o nome completo do tipo da classe que deseja carregar (por exemplo, Namespace.SubNamespace.ClassName ). Usando o método InvokeMember do Type classe você pode invocar métodos no tipo.

Além disso, leve em consideração que, uma vez carregado, um assembly não pode ser descarregado até que todo o AppDomain também seja descarregado (isso é basicamente um vazamento de memória).


2

Dependendo do quão intrínseco esse tipo de funcionalidade é para o seu projeto, você pode considerar algo como o MEF, que cuidará do carregamento e da união de componentes para você.


2
Assembly assembly = Assembly.LoadFrom("MyAssembly.dll");

Type type = assembly.GetType("MyType");

dynamic instanceOfMyType = Activator.CreateInstance(type);

Portanto, dessa maneira, você pode usar funções que não sejam a obtenção de methodinfo e, em seguida, invocá-lo. Você fará isso como instanceOfMyType.MethodName (); Mas você não pode usar o Intellisense porque os tipos dinâmicos são digitados em tempo de execução, não em tempo de compilação.


1

Sim, você desejará usar o método Load estático na classe Assembly e, em seguida, chame e, em seguida, chame o método CreateInstance na instância Assembly retornada da chamada para Load.

Além disso, você pode chamar um dos outros métodos estáticos começando com "Load" na classe Assembly, dependendo de suas necessidades.


0

Você pode fazer isso desta maneira:

using System.Reflection;

Assembly MyDALL = Assembly.Load("DALL"); //DALL name of your assembly
Type MyLoadClass = MyDALL.GetType("DALL.LoadClass"); // name of your class
 object  obj = Activator.CreateInstance(MyLoadClass);
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.