c# – 为什么抽象类实现接口?

我看到抽象类实现接口的代码?为什么要这么做?我们可以直接将它们放在接口中,而不是将抽象成员放在接口中吗?

为什么会写这样的代码?目的或需求是什么?

最佳答案
假设您正在开发一个具有IStream接口的流行库,该库在整个库中的各种API中使用. IStream有以下方法:

int Read(byte[] buffer, int offset, int count);
void Write(byte[] buffer, int offset, int count);

但是,不要让人们直接实现该接口,而是强烈建议他们从您的抽象类Stream继承,它实现该接口,如下所示:

public abstract int Read(byte[] buffer, int offset, int count);
public abstract void Write(byte[] buffer, int offset, int count);

很多人都遵循你的建议,但不是每个人都阅读文档,所以有些人直接实现IStream.

现在你的库的下一个版本出来了.你真的很兴奋,因为你要为你的流实现异步操作.因此,您将以下方法添加到IStream:

Task<int> ReadAsync(byte[] buffer, int offset, int count);
Task WriteAsync(byte[] buffer, int offset, int count);

现在你去更新你的抽象类以使其编译.你可以将新方法抽象化,但事实证明,有一种不完全疯狂的替代方法(省略错误处理):

public virtual Task<int> ReadAsync(byte[] buffer, int offset, int count)
{
    return Task.Run(() => this.Read(buffer, offset, count));
}

public virtual Task WriteAsync(byte[] buffer, int offset, int count)
{
    return Task.Run(() => this.Write(buffer, offset, count);
}

对于许多真实的流类型,通常会采用不同的方式来处理异步读取和写入,并且它可能比这更有效数倍(这就是为什么它是虚拟的而不是密封的),但这可能只是对大多数消费者来说足够好

现在让我们来看看这两组人.从抽象类继承的人自动获得IStream.ReadAsync和IStream.WriteAsync的实现,而无需自己编写任何代码.他们的流也可以在新的花哨的异步API中原样使用,而不需要做任何工作,并且它有可能不会吮吸.

另一方面,实现该接口的人现在必须处理编写他们自己的那些IStream方法的实现,即使他们对使用异步API没兴趣.也许他们抛出NotSupportedException以使错误消失.现在他们需要确保他们不会调用可能有可能调用IStream.ReadAsync或IStream.WriteAsync的任何东西.他们不开心.他们不按照你的建议去做这件事,但仍然很难不同情.

这是一个抽象类实现接口的一大优势.实际上,有些人可能认为IStream根本不应该存在,并且抽象Stream类应该只出现在IStream所具有的所有API中.盲目猜测:也许这就是为什么有System.IO.Stream,但没有System.IO.IStream.虽然我个人更喜欢有IStream.

转载注明原文:c# – 为什么抽象类实现接口? - 代码日志