Tôi đã sử dụng những thứ như thế này trên các dự án trước đó, nhưng nó được một lúc. Có thể có các khuôn khổ ngoài kia làm việc này cho bạn.
Để viết riêng plug-in kiến trúc của bạn, về cơ bản bạn muốn xác định một giao diện cho tất cả các mô-đun để thực hiện, và đặt điều này trong một assembly chia sẻ của cả hai chương trình của bạn và các module:
public interface IModule
{
//functions/properties/events of a module
}
Sau đó, những người triển khai của bạn sẽ mã hóa các mô đun của họ cho assembly này, tốt hơn là với một constructor mặc định.
public class SomeModule : IModule {} ///stuff
Trong chương trình của bạn (giả module của bạn sẽ được biên dịch vào lắp ráp riêng của họ), bạn tải một tài liệu tham khảo một hội đồng có chứa một mô-đun, tìm ra loại mà thực hiện các giao diện mô-đun, và nhanh chóng chúng:
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);
});
Nếu bạn muốn biên dịch mã khi đang chạy: bạn tạo một đối tượng trình biên dịch, hãy cho nó biết những gì cần tham khảo (Hệ thống và phần chứa IModule, cộng với bất kỳ tham chiếu nào khác cần thiết), cho nó biên dịch tập tin nguồn thành hội,, tổ hợp. Từ đó, bạn nhận được các loại được xuất, bộ lọc giữ những loại thực hiện IModule và khởi tạo chúng.
//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));
Tìm hướng dẫn về kiến trúc trình cắm và tải assmeblies động để có cảm giác tốt hơn khi thực hiện loại công cụ này. Đây mới chỉ là khởi đầu. Một khi bạn nhận được những điều cơ bản xuống, bạn có thể bắt đầu làm một số điều thực sự mát mẻ.
Để xử lý siêu dữ liệu (mô-đun X có tên YYY và nên xử lý các sự kiện A, B và C): Hãy thử làm việc này với hệ thống kiểu của bạn. Bạn có thể tạo ra các giao diện khác nhau cho các chức năng/sự kiện khác nhau, hoặc bạn có thể đặt tất cả các chức năng trên một giao diện và đặt các thuộc tính (bạn khai báo chúng trong assembly chung) trên các lớp module, sử dụng các thuộc tính để khai báo sự kiện nào mô-đun nên đăng ký. Về cơ bản bạn muốn làm cho nó càng đơn giản càng tốt để mọi người viết các mô-đun cho hệ thống của bạn.
enum ModuleTypes { ChannelMessage, AnotherEvent, .... }
[Shared.Handles(ModuleTypes.ChannelMessage)]
[Shared.Handles(ModuleTypes.AnotherEvent)]
class SomeModule : IModule { ... }
hoặc
//this is a finer-grained way of doing it
class ChannelMessageLogger : IChannelMessage {}
class PrivateMessageAutoReply : IPrivateMessage {}
vui chơi!
Tôi rất muốn khuyên bạn nên sử dụng các khuôn khổ plugin hiện có như MEF hoặc System.AddIns; họ sẽ giúp bạn tiết kiệm rất nhiều đau đầu ống dẫn nước. –
Tôi cũng vậy, nhưng OP đã yêu cầu giải pháp phi khung.Cộng với những điều cơ bản là tốt đẹp để biết – dan
Nếu tôi có thể upvote này một lần nữa một vài lần, tôi sẽ. Tôi đã học được rất nhiều từ mã bạn cung cấp cách đây 3 năm. – caesay