Написание системы плагинов C #
-
21-08-2019 - |
Вопрос
Я пытаюсь написать систему плагинов, чтобы обеспечить некоторую расширяемость моего приложения, чтобы кто-то мог написать плагин (ы) для приложения, не прикасаясь к коду основного приложения (и рискуя что-то сломать).
У меня написан базовый интерфейс "IPlugin" (atm, пока ничего не реализовано).
Вот как я загружаюсь:
public static void Load()
{
// rawr: http://www.codeproject.com/KB/cs/c__plugin_architecture.aspx
String[] pluginFiles = Directory.GetFiles(Plugins.PluginsDirectory, "*.dll");
foreach (var plugin in pluginFiles)
{
Type objType = null;
try
{
//Assembly.GetExecutingAssembly().GetName().Name
MessageBox.Show(Directory.GetCurrentDirectory());
Assembly asm = Assembly.Load(plugin);
if (asm != null)
{
objType = asm.GetType(asm.FullName);
if (objType != null)
{
if (typeof(IPlugin).IsAssignableFrom(objType))
{
MessageBox.Show(Directory.GetCurrentDirectory());
IPlugin ipi = (IPlugin)Activator.CreateInstance(objType);
ipi.Host = Plugins.m_PluginsHost;
ipi.Assembly = asm;
}
}
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString(), "Unhandled Exception! (Please Report!)", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
}
}
}
Друг пытался помочь, но я действительно не понимал, в чем дело.
Структура папок для плагинов следующая:
\
\Плагины\
Все плагины ссылаются на библиотеку DLL с именем "Lab.Core.dll" в каталоге [root], и она отсутствует в каталоге плагинов из-за загрузки дублирующихся ссылок.
Система плагинов загружается с Lab.Core.dll, на который также ссылается мой исполняемый файл.Введите "IPlugin" также в Lab.Core.dll.Lab.Core.dll является, в точности как названо, ядром моего приложения.
Редактировать:
Вопрос:Почему / что это за исключение, которое я получаю, и как я могу его исправить?
ОКОНЧАТЕЛЬНОЕ РЕДАКТИРОВАНИЕ:
Итак, я решил переписать его после просмотра исходного кода, который мой друг написал для регулятора TF2.
Вот что у меня есть, и это работает:
public class TestPlugin : IPlugin {
#region Constructor
public TestPlugin() {
//
}
#endregion
#region IPlugin Members
public String Name {
get {
return "Test Plugin";
}
}
public String Version {
get {
return "1.0.0";
}
}
public String Author {
get {
return "Zack";
}
}
public Boolean OnLoad() {
MessageBox.Show("Loaded!");
return true;
}
public Boolean OnAllLoaded() {
MessageBox.Show("All loaded!");
return true;
}
#endregion
}
public static void Load(String file) {
if (!File.Exists(file) || !file.EndsWith(".dll", true, null))
return;
Assembly asm = null;
try {
asm = Assembly.LoadFile(file);
} catch (Exception) {
// unable to load
return;
}
Type pluginInfo = null;
try {
Type[] types = asm.GetTypes();
Assembly core = AppDomain.CurrentDomain.GetAssemblies().Single(x => x.GetName().Name.Equals("Lab.Core"));
Type type = core.GetType("Lab.Core.IPlugin");
foreach (var t in types)
if (type.IsAssignableFrom((Type)t)) {
pluginInfo = t;
break;
}
if (pluginInfo != null) {
Object o = Activator.CreateInstance(pluginInfo);
IPlugin plugin = (IPlugin)o;
Plugins.Register(plugin);
}
} catch (Exception) {
}
}
public static void LoadAll() {
String[] files = Directory.GetFiles("./Plugins/", "*.dll");
foreach (var s in files)
Load(Path.Combine(Environment.CurrentDirectory, s));
for (Int32 i = 0; i < Plugins.List.Count; ++i) {
IPlugin p = Plugins.List.ElementAt(i);
try {
if (!p.OnAllLoaded()) {
Plugins.List.RemoveAt(i);
--i;
}
} catch (Exception) {
Plugins.List.RemoveAt(i);
--i;
}
}
}
Решение
Похоже, у вас есть циклическая ссылка.Вы сказали, что ваши плагины ссылаются на Lab.Core.DLL, но вы также говорите, что плагины загружаются с Lab.Core.DLL.
Я неправильно понимаю, что здесь происходит?
Редактировать:Хорошо, теперь, когда вы добавили свой вопрос к вопросу...
Вам необходимо иметь Lab.Core.DLL доступ к загружаемому плагину, поскольку это зависимость.Обычно это означало бы наличие его в том же каталоге или в GAC.
Я подозреваю, что здесь замешаны более глубокие проблемы с дизайном, но это ваша непосредственная проблема.
Другие советы
Платформа управляемой расширяемости (MEF) - это новая библиотека в .NET, которая обеспечивает более широкое повторное использование приложений и компонентов.Используя MEF, .NET-приложения могут перейти от статической компиляции к динамической.Если вы создаете расширяемые приложения, расширяемые фреймворки и расширения приложений, то MEF для вас.
Редактировать:CodePlex исчезает - код был перенесен на Github только для архивирования: https://github.com/MicrosoftArchive/mef
В качестве дополнительного ответа я использую эти 2 интерфейса для реализации этого
///<summary>
///</summary>
public interface IPlugin {
///<summary>
///</summary>
string Name { get; }
///<summary>
///</summary>
string Description { get; }
///<summary>
///</summary>
string Author { get; }
///<summary>
///</summary>
string Version { get; }
///<summary>
///</summary>
IPluginHost Host { get; set; }
///<summary>
///</summary>
void Init();
///<summary>
///</summary>
void Unload();
///<summary>
///</summary>
///<returns></returns>
IDictionary<int, string> GetOptions();
///<summary>
///</summary>
///<param name="opcion"></param>
void ExecuteOption(int option);
}
///<summary>
///</summary>
public interface IPluginHost {
///<summary>
///</summary>
IDictionary<string, object> Variables { get; }
///<summary>
///</summary>
///<param name="plugin"></param>
void Register(IPlugin plugin);
}