我以前在项目中使用过这样的东西,但已经有一段时间了。可能有一些框架可以为您执行这种类型的操作。
要编写自己的插件架构,基本上要定义一个接口,让所有模块都实现它,并将其放在程序和模块都共享的程序集中:
public interface IModule
{
}
然后您的实现人员将根据此程序集编写他们的模块,最好使用默认构造函数。
public class SomeModule : IModule {} ///stuff
在您的程序中(假设您的模块将编译为自己的程序集),您需要加载包含模块的程序集引用,找到实现模块接口的类型,并对它们进行实例化。
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);
});
如果你想即时编译代码:你需要创建一个编译器对象,告诉它需要引用哪些程序集(包括System和包含IModule的那个程序集,以及任何其他必要的引用),然后告诉它将源文件编译成一个程序集。从中获取导出类型,过滤并保留实现IModule接口的类型,并对它们进行实例化。
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);
var dynamicModuleTypes = dynamicAssembly.CompiledAssembly.GetExportedTypes()
.Where(t => t.GetInterfaces().Contains(typeof(IMod.IModule)));
var dynamicModules = dynModType.Select(t => (IMod.IModule)Activator.CreateInstance(t));
查找有关插件架构和加载动态程序集的教程,以更好地了解如何进行此类操作。这只是一个开始。一旦掌握了基础知识,您就可以开始做一些非常酷的事情。
至于处理元数据(模块X命名为YYY,应处理事件A、B和C):
尝试将其纳入您的类型系统中。您可以为不同的功能/事件制作不同的接口,或者将所有功能放在一个接口上,并在模块类上使用属性(您将在共享程序集中声明这些属性),使用属性来声明模块应订阅哪些事件。基本上,您希望使人们为您的系统编写模块尽可能简单。
enum ModuleTypes { ChannelMessage, AnotherEvent, .... }
[Shared.Handles(ModuleTypes.ChannelMessage)]
[Shared.Handles(ModuleTypes.AnotherEvent)]
class SomeModule : IModule { ... }
或者
//this is a finer-grained way of doing it
class ChannelMessageLogger : IChannelMessage {}
class PrivateMessageAutoReply : IPrivateMessage {}
玩得开心!