0

全新的。

我想要实现的是拥有一个接口,外部人员实现它并在我的程序中加载“实现”并将其绑定到我的接口,所以我对此有一些疑问以及我需要什么限制满足。

1-对于实现我的接口的用户,我是给他一个包含我的接口的 dll,还是只给他源代码,然后他使用它并添加他的实现代码?

1.1- 如果 1 为真,在我的程序中,我使用哪个接口?我可以使用直接从我的代码加载的接口,还是我被迫使用我提供给用户的同一个 DLL 中的接口?

2-命名空间是否需要相同?例如,我这边的接口在命名空间 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 时,它​​给出了无法创建实例的异常。

我应该知道什么?

4

3 回答 3

3

典型的方法是创建一个放置所有合同(合同是接口)的项目。不应该有业务逻辑。然后由您自己的应用程序使用(实现逻辑),这是您可以提供给其他人以实现它的程序集。命名空间应该与使用的 dll 相同。

您可能希望做的是创建某种插件系统 编写 C# 插件系统

您可以使用您描述的两种方法,我个人更喜欢方法1。

需要更多代码来解释这一点。动态创建对象时首先考虑:你需要有一个简单的构造函数,不带任何参数,否则激活器将无法创建实例。

我假设方法 1 失败了,因为插件和消费者之间没有共享合同

于 2013-05-24T07:47:10.037 回答
0

关于您的第一个问题(1 - 是将接口作为 DLL 还是通过源代码分发),您必须分发 DLL。否则,.NET 运行时将不会认为接口是相同的,因为接口的用户和实现它的用户将拥有两个版本的 DLL。通常,您将为不包含您的程序的接口创建一个单独的 DLL。

关于问题 1.1,您必须从您的 DLL 中引用单独的接口 DLL,并且接口的用户/实现者也必须引用它。由于你们都使用相同的 DLL,因此命名空间将是相同的。

为了创建实例(关于方法 1 和方法 2),您必须创建类的实例,而不是接口的实例。所以你需要从某个地方知道类的类型。获取实现接口的所有类型中描述了一种方法。但您也可以从字符串创建它,如从字符串创建类实例中所述。

于 2013-05-24T08:18:04.487 回答
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 的异常在这里几乎没有用。

于 2013-05-24T08:19:13.710 回答