关于C#:将基类中最复杂的方法声明为虚方法

Declare most complex method in base class as virtual

我一直在读Jeffrey Richter的书clr via c_,他认为在基类中定义一个方法时,如果有一个方法要声明为虚方法,并且它有一些方便的重载,那么最复杂的方法应该是虚方法,其他方法应该保留为非虚方法。他举了一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Set {
    private Int32 m_length = 0;
    // This convenience overload is not virtual
    public Int32 Find(Object value) {
        return Find(value, 0, m_length);
    }
    // This convenience overload is not virtual
    public Int32 Find(Object value, Int32 startIndex) {
        return Find(value, startIndex, m_length - startIndex);
    }
    // The most feature-rich method is virtual and can be overridden
    public virtual Int32 Find(Object value, Int32 startIndex, Int32 endIndex) {
        // Actual implementation that can be overridden goes here...
    }
    // Other methods go here
}

这里的理性是什么?


答案是——干涸的原则——唯一的真理来源。有一种方法是最复杂的。B、C和D都使用其功能的子集。所以程序员是这样创建的,所有进一步的代码修改都是基于您保持A、B、C、D之间的关系的假设。如果您允许所有的B、C、D都是可重写的,那么您就打破了将其放入类中的想法。

代码可读性受到影响,人们阅读您的基类,撰写一张它如何工作的图片,然后阅读您的类,并认为他们刚刚学到的并不是您实现的情况。让团队努力工作。同样,当您5年后阅读代码时(如果需要的话)。


原因是所有更简单的方法都是通过调用虚方法实现的。如果这些是虚拟的,您可能会破坏此合同。通过只允许您更改此类的实现专门化,这些方法将遵循相同的约定。


只有一个实现,其他重载只是转发调用。使一个virtual有意义,因为当实现被覆盖时,转发仍将工作。


我同意Jeffrey的观点;让虚拟成员成为最复杂的成员是有意义的,因为对"较小"复杂成员的调用将调用最复杂的成员,因为它们是通过方法链接调用的。此外,最复杂的成员可能是包含执行函数所需的所有参数的成员,而不包含任何外部依赖项。

如果可以的话,我稍后会详细讨论这个问题。