我有一个简单的用C#编写的插件加载程序项目作为控制台应用程序。 PluginLoader使用我的自定义抽象类MyPlugin类型在“ plugins”文件夹中查找.dll文件。 MyPlugin是一个IDisposable,包含插件的基本信息,例如Name,Author,Order。包含抽象的初始化方法。
PluginLoader将插件加载到程序集中,实例化,然后按顺序初始化它们。
我有Foo和Bar插件。 Bar引用Foo,以访问其中的一个对象(字符串Foo)。但是关于Foo组装,我在Bar中得到FileNotFoundException。问题是,Foo类已明确加载并初始化。
如果我添加
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="plugins" />
</assemblyBinding>
</runtime>
这进入应用程序配置,FileNotFound异常消失了。但是然后我在Foo元素上得到了NullReferenceException。使用VisualStudio调试器,很明显实例不为null,并且所有对象都已设置。
PluginLoader代码
class Program
{
public static List<MyPlugin> Plugins = new List<MyPlugin>();
static void Main(string[] args)
{
LoadPlugins();
Console.ReadLine();
}
public static void LoadPlugins()
{
var pluginsDirectory = Directory.CreateDirectory("plugins");
List<FileInfo> fileInfos = pluginsDirectory.GetFiles("*.dll").ToList();
foreach (FileInfo fileInfo in fileInfos)
{
try
{
Assembly assembly = Assembly.Load(File.ReadAllBytes(fileInfo.FullName));
foreach (Type type in assembly.GetExportedTypes())
{
if (!type.IsSubclassOf(typeof(MyPlugin)) || !type.IsPublic || type.IsAbstract)
continue;
MyPlugin pluginInstance;
try
{
pluginInstance = (MyPlugin)Activator.CreateInstance(type);
}
catch (Exception ex)
{
throw new InvalidOperationException(
string.Format("Could not create an instance of plugin class \"{0}\".", type.FullName), ex);
}
Plugins.Add(pluginInstance);
}
}
catch (Exception ex)
{
throw new InvalidOperationException(
string.Format("Failed to load assembly \"{0}\".", fileInfo.Name), ex);
}
}
IOrderedEnumerable<MyPlugin> orderedPluginSelector =
from x in Plugins
orderby x.Order, x.Name
select x;
foreach (MyPlugin current in orderedPluginSelector)
{
try
{
current.Initialize();
}
catch (Exception ex)
{
// Broken plugins better stop the entire server init.
throw new InvalidOperationException(string.Format(
"Plugin \"{0}\" has thrown an exception during initialization.", current.Name), ex);
}
Console.WriteLine($"Plugin {current.Name} initialized!");
}
}
}
Foo插件
public class Plugin : MyPlugin
{
public override string Name => "Foo";
public override string Author => "Patrikk";
public static Plugin Instance;
public string Foo;
public Plugin()
{
Instance = this;
Order = 0;
}
public override void Initialize()
{
Foo = "Foo";
}
}
酒吧插件
public class Plugin : MyPlugin
{
public override string Name => "Bar";
public override string Author => "Patrikk";
public static string Bar;
public Plugin()
{
}
public override void Initialize()
{
Bar = "Bar";
Console.WriteLine(Foo.Plugin.Instance.Foo + Bar);
}
}
我真的不确定我缺少什么。 我试图创建一个PluginLoader,一个“核心”插件(Foo)和其他需要并依赖于核心插件的插件(Bar)。