Ответ 1
Раньше я использовал такие вещи на проектах, но это было давно. Есть, вероятно, рамки, которые делают такие вещи для вас.
Чтобы написать собственную архитектуру плагина, в основном вы хотите определить интерфейс для всех модулей для реализации и поместить это в сборку, совместно используемую как вашей программой, так и модулями:
public interface IModule
{
//functions/properties/events of a module
}
Затем ваши разработчики будут кодировать свои модули для этой сборки, предпочтительно с помощью конструктора по умолчанию.
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, и создаете их.
//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));
Посмотрите руководства по подключаемым архитектурам и загрузите динамические assmeblies, чтобы лучше понять, как это делать. Это только начало. Как только вы уберете основы, вы можете начать делать действительно классные вещи.
Как для обработки метаданных (модуль 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 {}
получайте удовольствие!