接口是否可以定义c#-constructor的签名

时间:2010-06-09 21:56:37

标签: c# .net

我有一个.net-app,它提供了一个使用插件扩展应用程序的机制。每个插件必须实现一个插件接口,并且还必须提供一个接收一个参数(资源上下文)的构造函数。

在插件类的实例化期间,我通过反射查看,如果需要的构造函数存在,如果是,我实例化类(通过Reflection)。如果构造函数不存在,我抛出一个异常,说明不能创建插件,因为所需的构造函数不可用。

我的问题是,如果有一种方法可以在插件接口中声明构造函数的签名,那么实现插件接口的每个人都必须提供具有所需签名的构造函数。这样可以简化插件的创建。

我不认为存在这样的可能性,因为我认为这样的功能不属于设计接口的主要目的,但也许有人知道这样做的声明,如:

public interface IPlugin {
    ctor(IResourceContext resourceContext);
    int AnotherPluginFunction();
}

我想补充一点,我不想将构造函数更改为无参数,然后通过属性设置资源上下文,因为这会使插件的创建变得更加复杂。编写插件的人不是具有深度编程经验的人。插件用于计算应用程序可视化的统计数据。


感谢所有答案。

我已经决定,我让它成为一个接口,因为我不想强迫插件程序员从一个抽象类继承,以便他或她失去从一个自己的基类继承的可能性。此外,从抽象类派生并不能确保插件程序员真正提供所需的构造函数。它使它更有可能(程序员仍然有可能只添加一个包含所需参数的构造函数,但也有其他参数,这也很糟糕。请参阅Ken Browning答案的评论。)

虽然我在帖子中提到我不想要这样的属性,但我将Danny Varod的答案标记为已被接受,因为我认为在我的情况下这是最合适的解决方案。感谢所有回答的人。

7 个答案:

答案 0 :(得分:7)

接口不能声明构造函数。您可以考虑使用抽象类。

答案 1 :(得分:7)

插件可扩展性是我的最爱...

我所做的是确保插件实现接口或继承相应“插件套接字”的基类。

在某些地方,基类更合适(如果插件是一种X),
在某些接口中更合适(如果插件执行IX)。

我没有将上下文传递给构造,而是使用了一个属性和一个无参数的公共构造函数。

这样还可以使用反射更轻松地反序列化插件。

答案 2 :(得分:5)

不,这不存在。你可能在这里寻找一个抽象类。

答案 3 :(得分:1)

不幸的是,C#中的接口只能包含方法,属性,事件或索引器。

您可以使用并抽象所有插件将继承的类。在这种情况下,您可以强制它们实现构造函数签名。

答案 4 :(得分:1)

接口无法声明/强制执行构造函数。

定义接口创建一个抽象基类,它提供最有可能的构造函数实现 - 可能只是保存传入的资源上下文。

鼓励但不要求插件作者从基类派生。基类也可能提供其他有用的方法。

继续使用反射来检查插件。

答案 5 :(得分:1)

或者,您可以尝试使用工厂:使构造函数签名成为另一种类型的方法签名:

public abstract class PluginFactory
{
    public abstract IPlugin Create(IResourceContext context);
}

然后就像这样(如果我希望它缩短,我总是弄乱这部分,因此编辑):

public class PluginContainer
{
    public IPlugin LoadPlugin<T>(IResourceContext context) where T: PluginFactory, new()
    {
        var factory = new T();
        return factory.Create(context);
    }
}

答案 6 :(得分:0)

正如其他人所提到的,使用抽象类来处理管道细节是你想要完成的一个常见模式。如果使用者继承自抽象基类插件,这里有一种设计可以避免使用带有特殊参数的构造函数:

public interface IPlugin
{
    void Initialize(IResourceContext context);    

    //Other methods...
}

public abstract class Plugin : IPlugin
{
    protected IResourceContext Context { get; private set; }

    void IPlugin.Initialize(IResourceContext context)
    {
        Context = context;
    }

    //Abstract declaration of other methods...
}

您的代码必须在创建插件后在后台调用Initialize,但这个细节对于典型用户是隐藏的,因为他们通常不必直接实现IPlugin。您的典型用户只需定义一个插件后代并使用Context属性。

您可能还想查看各种依赖注入框架(例如Ninject),尽管它们可能对您所做的事情有些过分。尽管如此,看看它们如何工作可能会给你一些关于可以管理依赖注入的不同方法的想法。