为什么未密封 class 的未密封虚拟方法调用的顺序很重要?

Why does the ordering of the unsealed class`s unsealed virtual methods calls matter?

为什么未密封 class 的未密封虚拟方法调用的顺序很重要?

我正在探索 CLR via C# 一书,我发现了以下摘录:

When a class is originally sealed, it can change to unsealed in the future without breaking compatibility. However, once a class is unsealed, you can never change it to sealed in the future as this would break all derived classes. In addition, if the unsealed class defines any unsealed virtual methods, ordering of the virtual method calls must be maintained with new versions or there is the potential of breaking derived types in the future.

有人可以简单地解释一下以粗体突出显示的部分并(也许)提供一些示例吗?

我了解什么是 sealed/unsealed class/method 我了解什么是虚拟方法。但我不明白的是订购。摘录中提到的顺序是什么?

这是关于更改您的源代码 - 而不是关于构建 class 层次结构。

C# 中没有 "unsealed" 关键字,您不能从密封的 class 派生 class 并以任何方式声明生成密封的 "undone"。

您可以通过更改源代码删除关键字 "sealed" - 这是 "unsealing" 他们强调,这是一个非破坏性更改。所有引用您的代码的库都将继续工作。

这本书一定是关于代码审查或软件维护,或者库的演变而不是关于编程的。

下面是维护虚拟方法调用顺序很重要的场景:

class BaseClass
{
    public int Answer { get; protected set; }

    protected virtual void VM1() { Answer += 20; }
    protected virtual void VM2() { Answer += 10; }

    public void Init() { VM1(); VM2(); }
}

class DerivedClass : BaseClass
{
    private int _dividend;

    protected override void VM1() { Answer = _dividend = 20; }
    protected override void VM2() { Answer /= 10 }
}

现在假设你在某个地方有这个:

var baseObj = new BaseClass();
baseObj.Init();
int baseAnswer = baseObj.Answer;

var derivedObj = new DerivedClass();
derivedObj.Init();
int derivedAnswer = derivedObj.Answer;

baseAnswer 将包含 30derivedAnswer 将包含 2.

现在,假设 Init() 已更改,因此 VM2()VM1() 之前被调用。 baseAnswer 仍然包含 30 所以一切看起来都很好。但是,derivedAnswer 将包含 20(它是 2)!这就是我认为这本书警告你的那种情况。