这完全是新的。
我想要实现的是,有一个界面,来自外部的人实现它,并在我的程序中加载“实现”并将其绑定到我的界面,所以我有一些关于这个和有什么限制的问题我需要满足。
1-对于实现我的界面的用户,我给他一个包含我的界面的dll,或者只是源代码并且他使用它并添加他的实现代码?
1.1-如果1为真,在我的程序中,我使用哪个界面?我可以使用直接从我的代码加载的接口,或者我强制使用我给用户的同一个DLL的接口吗?
2- Do名称空间需要相同吗?例如,我这边的接口在命名空间Server.Interface中,但是我发送的dll中的接口只是命名空间接口。
我尝试了两种方法来验证程序集是否实现了我的接口:
都在循环中:
foreach (Type t in plugin.GetTypes())
{
方法1
if (typeof(INovedades).IsAssignableFrom(t))
{
i = (INovedades)Activator.CreateInstance(t);
break;
}
方法2
Type typeInterface = t.GetInterface("CapaDatos.ServiciosExternos.INovedades", true);
if (typeInterface != null)
{
i = (INovedades)Activator.CreateInstance(t);
break;
}
方法1始终为假,这意味着它永远不会验证。
方法2,找到匹配项,但是在调用CreateInstance时,它会给出一个关于无法创建实例的异常。
我应该知道什么?
答案 0 :(得分:3)
典型的方法是创建一个项目,其中放置所有合同(合同是接口)。应该没有业务逻辑。 然后由您自己的应用程序(实现逻辑)使用它,这是您可以提供给其他人实现它的程序集。 命名空间应该与使用的dll相同。
您可能希望做的是创建某种插件系统 Writing C# Plugin System
您可以使用您描述的两种方法,我个人更喜欢方法1。
需要更多代码来解释这一点。 首先考虑动态创建对象时:您需要一个没有任何参数的简单构造函数,否则激活器将无法创建实例。
我认为方法1失败,因为插件和消费者之间没有共享契约
答案 1 :(得分:0)
关于您的第一个问题(1 - 是将接口分发为DLL还是通过源代码分发),您必须分发DLL。否则,.NET Runtime将不会将接口视为相同,因为接口的用户和实现它的用户将具有两个版本的DLL。 通常,您将为不包含程序的接口创建单独的DLL。
关于问题1.1,您必须从DLL引用单独的接口DLL,并且接口的用户/实现者也必须引用它。 由于您都使用相同的DLL,因此名称空间将是相同的。
为了创建实例(关于方法1和方法2),您必须创建类的实例,而不是接口的实例。所以你需要从某个地方知道类的类型。 Getting all types that implement an interface中描述了一种方法。 但您也可以从字符串创建它,如Create class instance from string中所述。
答案 2 :(得分:0)
根据我在DLL-s(又名插件)中实现接口的经验,我使用过:
namespace TransportInterface
{
public interface Transport
{
string Name { get; }
// etc
}
}
将其编译成DLL文件TransportInterface.dll
之后,将此DLL作为参考添加到 1)应用程序本身的项目 2)使用此接口创建的任何插件的项目
实现此接口的插件:
namespace IRCTransport
{
public class IRCTransport : Transport
{
// here's the implementation
}
}
这里是从应用程序的项目加载插件(来自你的帖子的方法#2)
using TransportInterface;
// ...
private void LoadTransportPlugins()
{
string folder = System.AppDomain.CurrentDomain.BaseDirectory + "\\Transports";
string[] files = Directory.GetFiles(folder, "*.dll");
foreach (string file in files)
try
{
Assembly assembly = Assembly.LoadFile(file);
foreach (Type type in assembly.GetTypes())
{
Type iface = type.GetInterface("TransportInterface.Transport");
if (iface != null)
{
try
{
Transport plugin = (Transport)Activator.CreateInstance(type);
// executing this code means transport creation succeded
}
catch (Exception ex)
{
_System(ex.InnerException.Message + '\n', Color.Red);
}
AnyPlugins = true;
}
}
}
catch { };
}
这是几年前在.NET 3.5上写的,但我想从来没有任何改变。
所有三个名称空间: 1)'传输'界面 2)实现接口的插件 3)使用插件的应用程序
是不同的,我怀疑它们实际上需要是相同的。
如果你只是得到一个无法创建实例的例外,我想你需要验证插件构造不会触发任何异常。您需要更深入地使用“InnerException”调试此案例(可能甚至更多一次),这应该显示您的实际错误是什么,Activator的异常在这里几乎没用。