在Interface中定义可选的实现方法?

时间:2009-07-24 05:17:27

标签: c# .net-3.5

是否可以使用可选的实现方法定义接口?例如,我的核心库中有以下接口定义作为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();
   }

当然,我可以删除throw异常代码并将其留空。

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

无论如何,不​​确定是否可以将此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#中的接口中定义可选的实现方法?

6 个答案:

答案 0 :(得分:7)

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

  

然而,在我目前   实现,Stop()方法有   从未使用或实施过。在所有   我的实现类,这个方法   必须用throw实现   默认情况下NotImplementedExcetion():

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

  1. 从界面中删除Stop()方法。如果接口的每个实现者都没有使用它,那么显然不属于
    • 将接口转换为抽象基类,而不是接口。这样就不需要覆盖空的Stop()方法,直到你需要。
  2. 更新我认为方法可选的唯一方法是将方法分配给变量(类似于方法签名的委托类型),然后在尝试之前评估方法是否为null在任何地方都可以打电话。

    这通常是针对事件处理程序完成的,其中处理程序可能存在也可能不存在,并且可以视为可选。

答案 1 :(得分: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);
}

(或您的界面的等效物)。如果您针对具体类型提供更专业的版本,那么它将优先(但仅当调用者知道变量具体类型,而不是接口时)。因此,如上所述,任何人故意使用List<T>仍然使用List<T>的{​​{1}}版本;但如果有一个AddRange但只知道它为List<T>,它将使用扩展方法。

答案 2 :(得分:5)

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

但是,最好只在实际需要时将内容放入界面中 - 如果您仍处于可以删除{{1}}的位置,如果我是你,我会这样做。

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

答案 3 :(得分:4)

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

答案 4 :(得分:0)

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

最好的问候

答案 5 :(得分:0)

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

    }
}