反射实现接口

本文关键字:接口 实现 反射 | 更新日期: 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的异常在这里几乎没有用处。