C# 在接口中定义可选的实现方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1175832/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 10:03:34  来源:igfitidea点击:

Define optional implementation methods in Interface?

c#.net-3.5

提问by David.Chu.ca

Is it possible to define an Interface with optional implementation methods? For example I have the following interface definition as IDataReader in my core library:

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

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

However, in my current implementations, the Stop() method has never been used or implemented. In all my implementation classes, this method has to be implemented with throw NotImplementedExcetion() as default:

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

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

Of course, I can remove the throw exception code and leave it empty.

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

When I designed this data reader interface, I thought it should provide a way to stop the reading process. Maybe we will use Stop() sometime in the future.

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

Anyway, not sure if it is possible to make this Stop() method as an optional implementation method? The only way I can think is to either to define two interfaces one with stop and another without such as IDataReader and IDataReader2. Another option is to break this one into to interfaces like this:

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

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

 interface IStop {
    void Stop();
 }

In my implementation cases, I have to cast or use as IStop to check if my implementation supports Stop() method:

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

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

Still I have to write those codes. Any suggestions? Not sure if there is any way to define optional implementation methods in an interface in .Net or C#?

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

采纳答案by Marc Gravell

For info, another approach fairly common in the BCL is Supports*on the same interface, i.e.

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

bool SupportsStop {get;}
void Stop();

(examples of this, for example, in IBindingList).

(这方面的例子,例如,在IBindingList)。

I'm not pretending that it is "pure" or anything, but it works - but it means you now have twomethods to implement per feature, not one. Separate interfaces (IStoppableReader, for example) may be preferable.

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

For info, if the implementation is common between allimplementations, then you can use extension methods; for a trivial example:

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

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

(or the equivalent for your interface). If you provide a more specialized version against the concrete type, then it will take precedence (but only if the caller knows about the variable asthe concrete type, not the interface). So with the above, anyone knowingly using a List<T>still uses List<T>'s version of AddRange; but if the have a List<T>but only know about it as IList<T>, it'll use the extension method.

(或等效于您的界面)。如果您针对具体类型提供更专业的版本,那么它将优先(但前提是调用者知道变量具体类型,而不是接口)。因此,根据上述内容,任何有意使用List<T>仍然使用List<T>的版本的人都可以使用AddRange; 但如果有List<T>但只知道它 as IList<T>,它将使用扩展方法。

回答by Pavel Minaev

If no classes in your code actually implement Stop(), and you don't have definiteplans to do so in the future, then you don't need it in your interface. Otherwise, if somebut not allof your objects are "stoppable", then the correct approach is indeed to make it a separate interface such as IStoppable, and the clients should then query for it as needed.

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

回答by Oliver Hanappi

If your implementation does not implement the interface method Stop, then it breaks obviousily the contract that comes with your interface. Either you implement the Stop method appropriately (not by throwing an Exception and not by leaving it empty) or you need to redesign your interface (so to change the contract).

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

Best Regards

此致

回答by Jon Limjap

Interesting. I'll have to quote you here:

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

However, in my current implementations, the Stop() method has never been used or implemented. In all my implementation classes, this method has to be implemented with throw NotImplementedExcetion() as default:

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

If this is the case, then you have two options:

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

  1. Remove the Stop() method from the interface. If it isn't used by everyimplementor of the interface, it clearly does not belong there.
    • Instead of an interface, convert your interface to an abstract base class. This way there is no need to override an empty Stop() method until you need to.
  1. 从界面中删除 Stop() 方法。如果接口的每个实现者没有使用它,那么它显然不属于那里
    • 而不是接口,将您的接口转换为抽象基类。这样就不需要覆盖空的 Stop() 方法,除非你需要。

UpdateThe only way I think methods can be made optional is to assign a method to a variable (of a delegate type similar to the method's signature) and then evaluating if the method is null before attempting to call it anywhere.

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

This is usually done for event handlers, wherein the handler may or may not be present, and can be considered optional.

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

回答by Jon Skeet

If the method is inappropriate for your implementation, throw InvalidOperationExceptionjust like most iterators do when you call Reseton them. An alternative is NotSupportedExceptionwhich tends to be used by System.IO. The latter is more logical (as it has nothing to do with the current state of the object, just its concrete type) but the former is more commonly used in my experience.

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

However, it's best to only put things into an interface when you actually need them - if you're still in a position where you can remove Stop, I would do so if I were you.

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

There's no unified support for optional interface members in the language or the CLR.

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

回答by zproxy

C# version 4 (or vNext) is considering default implementation for interfaces- I heard that on channel9a few months ago ;).

C# 版本 4(或 vNext)正在考虑接口的默认实现- 我几个月前在channel9上听说过;)。

Interfaces with default implementation would behave somewhat like abstract base classes. Now that you can inherit multiple interfaces this could mean that C# might get multiple inheritance in form of interfaces with default implementations.

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

Until then you might get away with extension methods...

在那之前,您可能会使用扩展方法……

Or your type could make use of the delegates.

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

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

    }
}