反射实现接口
本文关键字:接口 实现 反射 | 更新日期: 2023-09-27 18:15:03
这是全新的
我想要实现的是有一个接口,外部的人实现它,在我的程序中加载"实现"并将其绑定到我的接口,所以我对此有一些问题,以及我需要满足哪些限制。
1-用户实现我的接口,我给他一个dll包含我的接口,或只是源代码,他使用它并添加他的实现代码?
1.1-如果1为真,在我的程序中,我使用哪个接口?我可以使用直接从我的代码加载的接口或我被迫使用从相同的DLL我给用户的接口?
2-名称空间需要相同吗?例如,我这边的接口位于名称空间Server中。接口,但是我发送的dll中只是命名空间接口。
我正在尝试两种方法来验证程序集是否实现了我的接口:
都在循环内:
foreach (Type t in plugin.GetTypes())
{
Method1
if (typeof(INovedades).IsAssignableFrom(t))
{
i = (INovedades)Activator.CreateInstance(t);
break;
}
Method2
Type typeInterface = t.GetInterface("CapaDatos.ServiciosExternos.INovedades", true);
if (typeInterface != null)
{
i = (INovedades)Activator.CreateInstance(t);
break;
}
方法1,总是false,这意味着它永远不会验证。
方法2,找到一个匹配,但是当调用CreateInstance时,它给出一个关于不能创建实例的异常。
有什么我应该知道的吗?
典型的方法是创建一个项目,其中放置了所有的合同(合同是接口)。不应该有业务逻辑。然后由您自己的应用程序(实现逻辑)使用它,您可以向其他应用程序提供该程序集来实现它。命名空间应该与使用的dll相同。
你可能想做的是创建一个插件系统编写c#插件系统
你可以使用你描述的两种方法,我个人更喜欢method1。
需要更多的代码来解释这个。首先考虑动态创建对象时:您需要有一个没有任何参数的简单构造函数,否则激活器将无法创建实例。
我认为方法1是失败的,因为插件和消费者之间没有共享契约
关于你的第一个问题(1 -是将接口作为DLL分发还是通过源代码分发),你必须分发DLL。否则,. net运行时将不会认为接口是相同的,因为接口的用户和实现它的人将拥有两个版本的DLL。通常,您将为不包含您的程序的接口创建一个单独的DLL。
关于问题1.1,你必须从你的DLL中引用那个单独的接口DLL,接口的用户/实现者也必须引用它。因为你们都使用相同的DLL,所以命名空间将是相同的。
为了创建实例(关于方法1和方法2),您必须创建类的实例,而不是接口的实例。所以你需要从某处知道类的类型。获取实现接口的所有类型中描述了一种方法。但是您也可以从字符串创建它,如从字符串创建类实例中所述。
根据我在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的异常在这里几乎没有用处。