He usado este tipo de cosas en los proyectos antes, pero ha sido Un rato. Probablemente hay marcos por ahí que hacen este tipo de cosas para usted.
para escribir su propia arquitectura plug-in, básicamente desea definir una interfaz para todos los módulos para implementar y poner esto en un ensamblado compartido tanto por su programa y los módulos:
public interface IModule
{
//functions/properties/events of a module
}
Entonces sus implementadores codificarán sus módulos en este ensamblaje, preferiblemente con un constructor predeterminado.
public class SomeModule : IModule {} ///stuff
En su programa (suponiendo sus módulos se compila en sus propias asambleas) se carga una referencia a un conjunto que contiene un módulo, encontrará los tipos que implementan la interfaz del módulo, y crean instancias:
var moduleAssembly = System.Reflection.Assembly.LoadFrom("assembly file");
var moduleTypes = moduleAssembly.GetTypes().Where(t =>
t.GetInterfaces().Contains(typeof(IModule)));
var modules = moduleTypes.Select(type =>
{
return (IModule) Activator.CreateInstance(type);
});
Si desea compilar el código sobre la marcha: crea un objeto compilador, le dice qué ensamblajes de referencia (el sistema y el que contiene IModule, más cualquier otra referencia necesaria), dígale que compile el archivo fuente en una montaje. A partir de eso, obtienes los tipos exportados, filtra los que mantienen aquellos que implementan el IModule y los instancias.
//I made up an IModule in namespace IMod, with string property S
string dynamicCS = @"using System; namespace DYN
{ public class Mod : IMod.IModule { public string S
{ get { return \"Im a module\"; } } } }";
var compiler = new Microsoft.CSharp.CSharpCodeProvider().CreateCompiler();
var options = new System.CodeDom.Compiler.CompilerParameters(
new string[]{"System.dll", "IMod.dll"});
var dynamicAssembly= compiler.CompileAssemblyFromSource(options, dynamicCS);
//you need to check it for errors here
var dynamicModuleTypes = dynamicAssembly.CompiledAssembly.GetExportedTypes()
.Where(t => t.GetInterfaces().Contains(typeof(IMod.IModule)));
var dynamicModules = dynModType.Select(t => (IMod.IModule)Activator.CreateInstance(t));
Mirar hacia arriba tutoriales en arquitecturas plug-in y la carga de assmeblies dinámicos para tener una mejor idea de hacer este tipo de cosas. Este es solo el comienzo. Una vez que hayas aprendido lo básico, puedes comenzar a hacer cosas realmente geniales.
En cuanto al manejo de los metadatos (el módulo X se llama YYY y debe manejar los eventos A, B y C): Trate de trabajar esto en su sistema de tipos. Podría crear diferentes interfaces para las diferentes funciones/eventos, o podría poner todas las funciones en una interfaz y poner atributos (los declararía en el ensamblado compartido) en las clases de módulos, usando los atributos para declarar qué eventos el módulo debe suscribirse a. Básicamente, debe hacer que sea lo más simple posible para las personas escribir módulos para su sistema.
enum ModuleTypes { ChannelMessage, AnotherEvent, .... }
[Shared.Handles(ModuleTypes.ChannelMessage)]
[Shared.Handles(ModuleTypes.AnotherEvent)]
class SomeModule : IModule { ... }
o
//this is a finer-grained way of doing it
class ChannelMessageLogger : IChannelMessage {}
class PrivateMessageAutoReply : IPrivateMessage {}
divertirse!
Recomiendo encarecidamente el uso de marcos de plugins existentes como MEF o System.AddIns; te ahorrarán muchos dolores de cabeza de plomería. –
Yo también, pero el OP solicitó una solución que no sea de marco.Además, lo básico es bueno saber – dan
Si pudiera volver a votar esto varias veces, lo haría. Aprendí mucho del código que me diste hace 3 años. – caesay