gpt4 book ai didi

C# - 何时调用 base.On Something?

转载 作者:太空宇宙 更新时间:2023-11-03 18:39:37 24 4
gpt4 key购买 nike

我正在使用 Windows.Forms 并且必须继承一些控件以提供自定义行为。这种继承显然会导致方法重写。

那么,问题来了 - 在哪些情况下调用 base.OnSomething(...) 的顺序真的会影响程序的可见行为?

protected override OnRetrieveVirtualItem(RetrieveVirtualItemEventArgs e)
{
// base.OnRetrieveVirtualItem(e); - Could this potentially break something?

// Perform your custom method.
// ...

base.OnRetrieveVirtualItem(e); // Is this always "correct"?
}

据我所知,在重写与绘画相关的方法(OnDrawItem, ...)时,这个顺序可能很重要,但我想 还有一些其他的射击方式 因为 Windows.Forms 进行了大量非托管代码调用,可能会产生副作用。

那么,什么时候可能重要?在这些情况下,选择正确位置调用 base 方法的经验法则是什么?

最佳答案

当 API 的文档指定您应该这样做时,您只需要调用 base.SomeVirtualMethod。否则,它应该被暗示为可选的。要求您调用基本方法但未明确说明的 API 设计不当。

需要基调用的原因是糟糕的设计,因为您永远无法预料覆盖您的方法的人会做什么,并且您无法确定他们会调用基方法来执行任何必需或关键的代码。

所以简而言之,引用文档,否则通常没有必要。 .NET Framework 是根据此类准则设计的,出于这些原因,大多数虚拟方法不需要调用基类。执行的操作已记录在案。

感谢 roken,他指出调用基本虚方法的一个非常重要的原因是在使用事件时。但是,我的反驳论点仍然适用,特别是如果您使用的是不遵循 .NET 惯用语和模式的第三方库或类,则没有任何确定性。举个例子。

namespace ConsoleApplication12
{
using System;
using System.Diagnostics;

class Foo
{
public Foo() {
}

public event EventHandler Load;

protected virtual void OnLoad() {
EventHandler handler = Load;

if (handler != null) {
handler(this, new EventArgs());
}

Debug.WriteLine("Invoked Foo.OnLoad");
}

public void Run() {
OnLoad();
}
}

class DerivedFoo : Foo
{
protected override void OnLoad() {
base.OnLoad();
Debug.WriteLine("Invoked DerivedFoo.OnLoad");
}
}

class Program
{
static void Main(string[] args) {
DerivedFoo dFoo = new DerivedFoo();

dFoo.Load += (sender, e) => {
Debug.WriteLine("Invoked dFoo.Load subscription");
};

dFoo.Run();
}
}
}

如果运行此示例,您将获得对 Foo.OnLoadDerivedFoo.OnLoad 和事件订阅 dFoo.Load 的三个调用>。如果您在 DerivedFoo 中注释掉对 base.OnLoad 的调用,您现在将只会获得对 DerivedFoo.OnLoad 的一次调用,而基订阅者没有接到电话。

关键在于文档。仍然不确定基本虚方法实现是否会调用其订阅者。所以这应该很清楚。幸运的是,由于框架设计者,.NET Framework 与 .NET 事件模型非常一致,但我仍然无法承受足够大的压力来阅读 API 的文档。

当您根本不处理事件,而是处理抽象基类之类的事情时,它会发挥很多作用。你怎么知道是否调用抽象类的基事件?抽象类是提供默认实现,还是希望您提供它?

文档是为虚拟成员(member)定义契约(Contract)的最有力、最清晰的方式。这就是为什么 .NET Framework 设计团队通常为交付的抽象类至少提供一个具体实现的原因之一。

我认为 Krzysztof Cwalina 在框架设计指南中说得最好。

A common question I get is whether documentation for virtual members should say that the overrides must call the base implementation. The answer is that overrides should preserve the contract of the base class. They can do it by calling the base implementation or by some other means. It is rare that a member can claim that the only way to preserve its contract (in the override) is to call it. In a lot of cases, calling the base might be the easiest way to preserve the contract (and docs should point that out), but it's rarely absolutely required.

我完全同意。如果您重写了一个基本实现并决定不调用它,您应该提供相同的功能。

我希望这能消除我在评论中的一些困惑。

关于C# - 何时调用 base.On Something?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10381279/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com