El mecanismo de reflexión proporcionado por .NET puede cargar complementos fácilmente. Este artículo proporciona un método que puede cargar de forma flexible y correcta los complementos necesarios.
En .NET, un nombre de tipo completo tiene el formato "nombre de tipo, nombre de ensamblado".
Por ejemplo: "System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089".
El nombre del tipo es: System.Configuration.NameValueSectionHandler, que es el nombre del tipo completo con espacio de nombres.
También puede obtener el nombre completo utilizando el tipo.
Por ejemplo: cadena typeName = typeof(NameValueSectionHandler).FullName;
El nombre del ensamblado es: "Sistema, Versión=1.0.3300.0, Cultura=neutral, PublicKeyToken=b77a5c561934e089",
El ensamblado se denomina Sistema y el sistema adapta automáticamente su extensión (como System.dll o System.exe);
Versión, Cultura y PublicKeyToken son la versión específica, el trasfondo cultural y la firma del ensamblado. No existen requisitos específicos y se pueden omitir.
Podemos cargar dinámicamente un tipo requerido según el nombre del tipo. como:
string typeName = "System.Configuration.NameValueSectionHandler, System";
Escriba t = Type.GetType(typeName);
Objeto obj = Activator.CreateInstance(t);
//o
System.Configuration.NameValueSectionHandler obj = (System.Configuration.NameValueSectionHandler)Activator.CreateInstance(t);
En este punto, obj es la instancia de tipo requerida.
Por lo general, los complementos son clases que necesitan implementar determinadas interfaces. Por lo tanto, antes de cargar un complemento, debe determinar si el tipo de complemento es apropiado.
Por ejemplo, si la interfaz de un complemento es IPlugin, podemos identificarlo de la siguiente manera:
cadena nombreinterfaz = tipode(IPlugin).NombreCompleto;
string typeName = "Muf.MyPlugin, MyPlugin";
Escriba t = Type.GetType(typeName);
si (t == nulo
|| !t.EsClase
|| !t.EsPúblico
|| t.GetInterface(nombredeinterfaz) == nulo)
{
return null; // No es el complemento requerido
}
Resumiendo el código anterior, podemos crear un código general para cargar complementos:
/**//// <resumen>
/// Carga y crea dinámicamente un tipo que tiene la interfaz especificada
/// </summary>
/// <param name="className">Nombre del tipo</param>
/// <param name="interfaceName">Nombre de interfaz especificada</param>
/// <param name="param">Especifique los parámetros del constructor (una matriz nula o vacía significa llamar al constructor predeterminado)</param>
/// <returns>Devuelve el tipo creado (nulo significa que el tipo no se puede crear o no se puede encontrar)</returns>
objeto estático público LoadObject (cadena nombre de clase, cadena nombre de interfaz, objeto [] parámetro)
{
intentar
{
Escriba t = Type.GetType(className);
si (t == nulo
|| !t.EsClase
|| !t.EsPúblico
|| t.EsAbstracto
|| t.GetInterface(nombredeinterfaz) == nulo)
{
devolver nulo;
}
objeto o = Activator.CreateInstance(t, parámetro);
si (o == nulo)
{
devolver nulo;
}
volver o;
}
captura (Excepción ex)
{
devolver nulo;
}
}
Más adelante, podemos usar LoadObject para cargar los complementos necesarios.
Los complementos generalmente se colocan en archivos de configuración y el programa los lee:
Ejemplos de archivos de configuración (consulte mis ensayos relacionados para el uso de archivos de configuración):
<?xml version="1.0" encoding="utf-8" ?>
<configuración>
<secciones de configuración>
<nombre de sección="Canales" tipo="Vmp.Configuration.ChannelsSectionHandler, Comunicación" />
</configSections>
<Canales>
<canal
ChannelType="Vmp.Comunicación.TcpChannel, Comunicación"
TraceFile="d:logchannel1.log"
Puerto="2020" MaxConnections="300" BufferSize="2048"
/>
</Canales>
</configuración>
Ejemplo de código:
lista de canales privada ArrayList = nueva ArrayList()
privada LoadChannels()
;
{
ArrayList canalesConfig = (ArrayList)ConfigurationSettings.GetConfig( "Canales" );
foreach (configuración de tabla hash en canalesConfig)
{
string channelType = (cadena) config["ChannelType"];
canal IChannel = (IChannel) CommonUtils.LoadObject(channelType, typeof(IChannel).FullName, nuevo objeto[]{config});
si (canal == nulo)
continuar;
canalesList.Add(canal);
}
También puede recorrer el directorio de complementos especificado y cargar todos los complementos que cumplan con los requisitos, por ejemplo:
public IPlugin[] LoadAllPlugIn(string pluginDir)
{
//Establece el directorio de complementos predeterminado
if(pluginDir == nulo || pluginDir == "")
pluginDir = "./PlugIns"
// Obtener el nombre de la interfaz del complemento
string interfaceName = typeof(IPlugin).FullName
// Matriz utilizada para almacenar complementos.
ArrayList arr = new ArrayList();
// Recorre el directorio del complemento (suponiendo que el complemento es un archivo dll)
foreach(archivo de cadena en Directory.GetFiles(pluginDir, "*.dll"))
{
//Carga el archivo del complemento
Asamblea asm = Asamblea.LoadFile(archivo);
// Recorre las clases de complementos exportadas
foreach(Escriba t en asm.GetExportedTypes())
{
//Carga el complemento. Si el complemento no se ajusta a la interfaz especificada, devuelve nulo.
Complemento IPlugin = LoadObject(t.FullName, interfaceName, null) como IPlugin
if(plugin!= null)
arr.Add(complemento);
}
}
// Volver al complemento
return (IPlugin[])arr.ToArray(typeof(IPlugin));
}