我正在开发一个使用插件的程序。所有插件都是继承自KrotAPI.IKrotAPI接口的类。该接口存储在krotapi.cs文件中,这对于主机的csproj和每个插件'* .csproj都是通用的。
主机使用此代码加载插件
dynamic LoadPlugin(Assembly asm)
{
foreach (Type type in asm.GetTypes())
{
if (type.GetInterface("KrotAPI.IKrotPlugin") != null)
{
PluginType = type;
dynamic inst = Activator.CreateInstance(type);
KrotAPI.IKrotPlugin inst2 = inst as KrotAPI.IKrotPlugin;
if (inst2 == null) return inst;
Console.WriteLine("Link to API is set up.");
return inst2;
}
}
throw new Exception("There are no valid plugin(s) in the DLL.");
}
inst2
总是为空,我被迫使用慢速和错误的动态调用。如何使其像inst
,但KrotAPI.IKrotPlugin
类型?
关于几乎相同主题的第二个问题。 一些插件的函数返回KrotAPI.FindData类型的结果(它是一个结构,存储在krotapi.cs文件的上面)。但我无法访问它:
dynamic fd = new KrotAPI.FindData();
if (NextItemInfo != null) //NextItemInfo is an instance of that struct
fd = NextItemInfo;
listBox1.Items.Add(fd.FileName);
在最后一行.NET Framework引发此异常:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException 'System.ValueType'不包含'FileName'
的定义
然而,FileName字段在结构中是硬编码的,当然不是null或
Microsoft.CSharp.RuntimeBinder.RuntimeBinderInternalCompilerException 绑定动态操作时发生意外异常
如果我用KrotAPI.FindData fd2 = (KrotAPI.FindData) fd; listBox1.Items.Add(fd2.FileName);
替换最后一行。
WTF?
答案 0 :(得分:1)
您在主机和插件中定义了IKrotAPI
接口。这意味着它们不是同一个界面。包含程序集是界面完整标识的一部分。您的每个插件实际上都实现了一个在其自己的程序集中定义的接口,该接口与主机程序集中定义的接口不同。
有两种方法可以解决这个问题:
IKrotAPI
接口的主机程序集。KrotAPI.FindData
)创建第三个程序集。我个人更喜欢第二种方法。它允许您升级主机程序集而不会使现有插件失效。要为这种程序集使用通用命名约定,可以将此第三个程序集称为KrotAPI
。我倾向于将“API”视为某人(即插件开发人员)编写的接口和数据类型集,但在您的情况下,所有实际的可运行代码都将位于主机或插件中。 / p>