【问题标题】:Define optional implementation methods in Interface?在接口中定义可选的实现方法?
【发布时间】:2010-11-13 15:12:31
【问题描述】:

是否可以定义具有可选实现方法的接口?例如,我的核心库中有以下接口定义为 IDataReader:

public interface IDataReader<T> {
  void StartRead(T data);
  void Stop();
}

但是,在我当前的实现中,Stop() 方法从未被使用或实现过。在我所有的实现类中,这个方法必须默认使用 throw NotImplementedExcetion() 来实现:

class MyDataReader : IDataReader<MyData> {
   ...
   public void Stop()
   {
     // this none implementaion looks like uncompleted codes
     throw NotImplementedException();
   }

当然,我可以把抛出异常代码去掉,留空。

当我设计这个数据阅读器界面时,我认为它应该提供一种停止阅读过程的方法。也许我们将来某个时候会使用 Stop()。

无论如何,不​​确定是否可以将这个 Stop() 方法作为可选的实现方法?我能想到的唯一方法是定义两个接口,一个带停止,另一个不带 IDataReader 和 IDataReader2。另一种选择是将其分解为如下接口:

 interface IDataReader<T> {
    void StartRead(T data);
 }

 interface IStop {
    void Stop();
 }

在我的实现案例中,我必须强制转换或用作 Istop 来检查我的实现是否支持 Stop() 方法:

 reader.StartRead(myData);
 ....
 // some where when I need to stop reader
 IStop stoppable = reader as IStop;
 if (stoppable != null ) stoppable.Stop();
 ...

我仍然必须编写这些代码。有什么建议?不确定是否有任何方法可以在 .Net 或 C# 的接口中定义可选的实现方法?

【问题讨论】:

    标签: c# .net-3.5


    【解决方案1】:

    如果您的代码中没有任何类实际实现Stop(),并且您没有明确计划将来这样做,那么您的界面中就不需要它。否则,如果 some 而不是 all 您的对象是“可停止的”,那么正确的方法确实是使其成为一个单独的接口,例如IStoppable,并且客户端然后应该根据需要查询它。

    【讨论】:

      【解决方案2】:

      如果您的实现没有实现接口方法 Stop,那么它显然会破坏您的接口附带的合同。要么适当地实现 Stop 方法(不是通过抛出异常而不是将其留空),要么你需要重新设计你的界面(以便更改合同)。

      最好的问候

      【讨论】:

        【解决方案3】:

        有趣。我必须在这里引用你的话:

        但是,在我目前的 实现,Stop() 方法有 从未被使用或实施过。在所有 我的实现类,这个方法 必须用 throw 来实现 默认为 NotImplementedExcetion():

        如果是这种情况,那么您有两种选择:

        1. 从界面中删除 Stop() 方法。如果接口的每个实现者都没有使用它,那么它显然不属于那里
          • 将接口转换为抽象基类,而不是接口。这样,在您需要之前,无需重写空的 Stop() 方法。

        更新我认为可以使方法成为可选的唯一方法是将方法分配给变量(类似于方法签名的委托类型),然后在尝试之前评估该方法是否为空在任何地方调用它。

        这通常用于事件处理程序,其中处理程序可能存在也可能不存在,并且可以被认为是可选的。

        【讨论】:

        • 我明白你的意思。我实际上已经删除了该方法。这在我的控制之下。但是,在我这样做之后,我试图找出是否有任何方法可以在 .Net 中制作方法选项?我真的很喜欢将其保留为可选,以防我必须通过界面停止该过程。
        【解决方案4】:

        如果该方法不适合您的实现,请抛出 InvalidOperationException,就像大多数迭代器在对它们调用 Reset 时所做的一样。另一种选择是NotSupportedException,它往往被System.IO 使用。后者更合乎逻辑(因为它与对象的当前状态无关,只是它的具体类型),但在我的经验中前者更常用。

        但是,最好仅在您真正需要时才将它们放入界面中 - 如果您仍然处于可以删除 Stop 的位置,如果我是您,我会这样做。

        语言或 CLR 中没有对可选接口成员的统一支持。

        【讨论】:

        • .NET 中有 System.NotSupportedException ;)
        • 同意。看起来 C# 不支持可选实现。我有很多案例要使用未使用的方法来实现 .Net 核心接口。
        • @Oliver:是的。两者都有点混乱 - 我会编辑我的答案。
        【解决方案5】:

        C# 版本 4 (or vNext) 正在考虑使用 default implementation for interfaces - 我几个月前在 channel9 上听说过;)。

        具有默认实现的接口的行为有点像抽象基类。既然您可以继承多个接口,这可能意味着 C# 可能会以具有默认实现的接口形式获得多个继承。

        在那之前你可能会摆脱扩展方法...

        或者您的类型可以使用委托。

        interface IOptionalStop
        {
            Action Stop { get; }
        }
        
        public class WithStop : IOptionalStop
        {
            #region IOptionalStop Members
        
            public Action Stop
            {
                get;
                private set;
            }
        
            #endregion
        
            public WithStop()
            {
                this.Stop =
                    delegate
                    {
                        // we are going to stop, honest!
                    };
            }
        }
        
        public class WithoutStop : IOptionalStop
        {
            #region IOptionalStop Members
        
            public Action Stop
            {
                get;
                private set;
            }
        
            #endregion
        }
        
        
        public class Program
        {
            public static string Text { get; set; }
        
        
            public static void Main(string[] args)
            {
                var a = new WithStop();
        
                a.Stop();
        
                var o = new WithoutStop();
        
                // Stop is null and we cannot actually call it
                a.Stop();
        
            }
        }
        

        【讨论】:

        • C# 4.0 中没有“接口的默认实现”。
        • 太伤心了。我认为这应该很容易做到。只需在方法之前添加一个新的 key 指令 work Optional,这样 .net 编译器就会为此方法生成空的主体代码。如果未实现,则调用此可选方法将什么也不做,也不例外。当然,这可能会为人们扔进太多糟糕的接口打开一扇门。有一个可选的实现是有价值的,但它可能会被滥用。只是我的评论。
        • 我看到一些错别字。对此感到抱歉。现在在加拿大为时已晚。
        • 我给出的示例中的委托方法如何适用于当前版本的 c#?
        • 我喜欢它。我想到了代表,但没有你的那么干净。但是,我仍然检查委托是否为空,并定义另一个委托来实现。
        【解决方案6】:

        关于信息,BCL 中相当常见的另一种方法是Supports* 在同一界面上,即

        bool SupportsStop {get;}
        void Stop();
        

        (例如,IBindingList 中的示例)。

        我并不是假装它是“纯粹的”或任何东西,但它确实有效 - 但这意味着您现在有 两种 方法来实现每个功能,而不是一种。单独的接口(例如IStoppableReader)可能更可取。

        对于信息,如果实现在所有实现之间是通用的,那么您可以使用扩展方法;举个简单的例子:

        public static void AddRange<T>(this IList<T> list, IEnumerable<T> items) {
            foreach(T item in items) list.Add(item);
        }
        

        (或您的界面的等效项)。如果您针对具体类型提供更专业的版本,那么它将优先(但前提是调用者知道变量 as 是具体类型,而不是接口)。因此,在上述情况下,任何使用List&lt;T&gt; 的人仍然使用List&lt;T&gt;AddRange 版本;但是如果有List&lt;T&gt;但只知道IList&lt;T&gt;,它将使用扩展方法。

        【讨论】:

          猜你喜欢
          • 2021-09-30
          • 2020-05-02
          • 2016-03-03
          • 1970-01-01
          • 1970-01-01
          • 2023-03-17
          • 2019-01-08
          • 1970-01-01
          相关资源
          最近更新 更多