【问题标题】:Can an interface define the signature of a c#-constructor接口可以定义 c#-constructor 的签名吗
【发布时间】:2011-03-01 22:00:21
【问题描述】:

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

在插件类的实例化过程中,我通过反射查看,如果需要的构造函数存在,如果存在,我实例化该类(通过反射)。如果构造函数不存在,我会抛出一个异常,指出无法创建插件,因为所需的构造函数不可用。

我的问题是,是否有办法在插件接口中声明构造函数的签名,以便实现插件接口的每个人也必须提供具有所需签名的构造函数。这将简化插件的创建。

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

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

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


感谢大家的回答。

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

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

【问题讨论】:

    标签: c# .net


    【解决方案1】:

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

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

    在某些地方基类更合适(如果插件是X的一种),
    在某些界面上更合适(如果插件做IX的话)。

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

    这也使得使用反射更容易反序列化插件。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 抽象类也不能强制在其子类中创建构造函数,可以吗?
      • 如果你定义一个带参数的ctor,它们可以禁用无参数ctor的自动创建。这样,您就可以强制执行 ctor-chaining。除非基类具有无参数 ctor,否则您根本无法在不调用 basector 的情况下从类派生。
      • @Matthew Scharley,子类必须始终“调用”父类中的构造函数,因此如果父类没有无参数构造函数,则子类必须以某种方式在其构造函数中获取参数。这可能是通过在子节点上强制执行相同的构造函数,也可能不是,但这是一种确保提供父节点所需信息的方法
      • @JS 刘海。不,你不能stackoverflow.com/questions/504977/…
      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

        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);
            }
        }
        

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            【解决方案6】:

            接口不能声明/强制执行构造函数。

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

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

            继续使用反射检查插件。

            【讨论】:

              【解决方案7】:

              正如其他人所暗示的那样,使用抽象类来处理管道细节是您要完成的工作的常见模式。如果消费者从抽象基类 Plugin 继承,这是一种避免使用具有特殊参数的构造函数的设计:

              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),尽管它们对于您正在做的事情可能有点矫枉过正。尽管如此,看看它们是如何工作的,您可能会对管理依赖注入的不同方式产生一些想法。

              【讨论】:

                猜你喜欢
                • 2021-09-07
                • 1970-01-01
                • 2012-10-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-02-14
                • 1970-01-01
                • 2010-09-16
                相关资源
                最近更新 更多