1

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

我正在通过 C# 书探索 CLR,我遇到了以下摘录:

当一个类最初是密封的时,它可以在将来更改为未密封的,而不会破坏兼容性。但是,一旦一个类被解封,以后就永远不能将其更改为密封,因为这会破坏所有派生类。此外,如果未密封的类定义了任何未密封的虚拟方法,则必须使用新版本维护虚拟方法调用的顺序,否则将来可能会破坏派生类型。

有人可以以万无一失的方式解释以粗体突出显示的部分并(也许)提供一些例子吗?

我了解什么是密封/非密封类/方法,我了解什么是虚拟方法。但我不明白的是订购。摘录中提到的顺序是什么?

4

2 回答 2

1

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

C# 中没有“未密封”关键字,您不能从密封类派生类并以任何方式声明使密封“撤消”。

您可以通过更改源代码来删除关键字“sealed” - 这是“unsealing”并且他们强调,这是一个非破坏性更改。所有引用您的代码的库都可以使用。

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

于 2019-12-02T23:30:55.200 回答
1

这是一个维护虚拟方法调用顺序很重要的场景:

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将包含30并将derivedAnswer包含2.

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

于 2019-12-03T00:04:17.953 回答