O mecanismo de reflexão fornecido pelo .NET pode carregar plug-ins facilmente. Este artigo fornece um método que pode carregar de maneira flexível e correta os plug-ins necessários.
No .NET, um nome de tipo completo tem o formato "nome do tipo, nome do assembly".
Por exemplo: "System.Configuration.NameValueSectionHandler, Sistema, Versão=1.0.3300.0, Cultura=neutro, PublicKeyToken=b77a5c561934e089".
O nome do tipo é: System.Configuration.NameValueSectionHandler, que é o nome completo do tipo com namespace.
Você também pode obter o FullName usando o tipo.
Por exemplo: string typeName = typeof(NameValueSectionHandler).FullName;
O nome do assembly é: "System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
O assembly é denominado System e o sistema adapta automaticamente sua extensão (como System.dll ou System.exe);
Versão, Cultura e PublicKeyToken são a versão específica, o histórico cultural e a assinatura do assembly. Não há requisitos específicos e eles podem ser omitidos.
Podemos carregar dinamicamente um tipo necessário com base no nome do tipo. como:
string typeName = "System.Configuration.NameValueSectionHandler, Sistema";
Digite t = Type.GetType(typeName);
Objeto obj = Activator.CreateInstance(t);
//ou
System.Configuration.NameValueSectionHandler obj = (System.Configuration.NameValueSectionHandler)Activator.CreateInstance(t);
Neste ponto, obj é a instância de tipo necessária.
Normalmente plug-ins são classes que precisam implementar determinadas interfaces. Portanto, antes de carregar um plug-in, é necessário determinar se o tipo de plug-in é apropriado.
Por exemplo, se a interface de um plug-in for IPlugin, podemos identificá-la da seguinte forma:
string interfaceName = typeof(IPlugin).FullName;
string typeName = "Muf.MyPlugin, MyPlugin";
Digite t = Type.GetType(typeName);
se (t == nulo
|| !t.IsClass
|| !t.IsPublic
|| t.GetInterface(nomedainterface) == nulo)
{
return null; // Não é o plugin necessário
}
Resumindo o código acima, podemos fazer um código geral para carregar plug-ins:
/**//// <resumo>
/// Carrega e cria dinamicamente um tipo que possui a interface especificada
/// </sumário>
/// <param name="className">Nome do tipo</param>
/// <param name="interfaceName">Nome da interface especificada</param>
/// <param name="param">Especifique os parâmetros do construtor (matriz nula ou vazia significa chamar o construtor padrão)</param>
/// <returns>Retorna o tipo criado (null significa que o tipo não pode ser criado ou não pode ser encontrado)</returns>
objeto estático público LoadObject (string className, string interfaceName, object[] param)
{
tentar
{
Digite t = Type.GetType(className);
se (t == nulo
|| !t.IsClass
|| !t.IsPublic
|| t.IsAbstract
|| t.GetInterface(nomedainterface) == nulo)
{
retornar nulo;
}
objeto o = Activator.CreateInstance(t, param);
if(o == nulo)
{
retornar nulo;
}
retornar ó;
}
catch(Exceção ex)
{
retornar nulo;
}
}
Posteriormente, podemos usar LoadObject para carregar quaisquer plug-ins necessários.
Os plug-ins geralmente são colocados em arquivos de configuração e lidos pelo programa:
Exemplos de arquivos de configuração (veja meus ensaios relacionados sobre o uso de arquivos de configuração):
<?xml version="1.0" encoding="utf-8" ?>
<configuração>
<seções de configuração>
<section name="Canais" type="Vmp.Configuration.ChannelsSectionHandler, Comunicação" />
</configSections>
<Canais>
<canal
ChannelType="Vmp.Communication.TcpChannel, Comunicação"
TraceFile="d:logcanal1.log"
Porta="2020" MaxConnections="300" BufferSize="2048"
/>
</Canais>
</configuração>
Exemplo de código:
private ArrayList canaisList = new ArrayList()
;
{
ArrayList canaisConfig = (ArrayList)ConfigurationSettings.GetConfig( "Canais");
foreach (configuração hashtable em canaisConfig)
{
string channelType = (string) config["ChannelType"];
canal IChannel = (IChannel) CommonUtils.LoadObject(channelType, typeof(IChannel).FullName, novo objeto[]{config});
if(canal == nulo)
continuar;
canaisList.Add(canal);
}
Você também pode percorrer o diretório de plug-in especificado e carregar todos os plug-ins que atendam aos requisitos, por exemplo:
public IPlugin[] LoadAllPlugIn(string pluginDir)
{
//Define o diretório padrão do plugin
if(pluginDir == null || pluginDir == "")
pluginDir = "./PlugIns";
// Obtém o nome da interface do plug-in
string interfaceName = typeof(IPlugin).FullName;
// Array usado para armazenar plug-ins
ArrayList arr = new ArrayList();
// Percorre o diretório do plug-in (assumindo que o plug-in é um arquivo dll)
foreach(arquivo de string em Directory.GetFiles(pluginDir, "*.dll"))
{
//Carrega o arquivo do plug-in
Montagem asm = Assembly.LoadFile(arquivo);
// Percorre as classes de plug-in exportadas
foreach(Digite t em asm.GetExportedTypes())
{
//Carrega o plug-in Se o plug-in não estiver em conformidade com a interface especificada, retorne nulo.
Plugin IPlugin = LoadObject(t.FullName, interfaceName, null) as IPlugin
if(plugin != null)
arr.Add(plugin);
}
}
//Retorna ao plugin
return (IPlugin[])arr.ToArray(typeof(IPlugin));
}