C#-什么时候调用base.OnSomething? [英] C# - when to call base.OnSomething?

查看:110
本文介绍了C#-什么时候调用base.OnSomething?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm using Windows.Forms and have to inherit some controls to provide custom behavior. This inheritance obviously leads to method overriding.

所以,这是一个问题-在哪种情况下,调用base.OnSomething(...)的顺序确实会影响程序的可见行为?

So, here is the question - in which cases the order of calling base.OnSomething(...) can really affect the visible behavior of your program?

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进行了很多非托管代码调用,可能会有副作用.

As far as I know for know, this order can be important when overriding paint-related methods (OnDrawItem, ...), but I guess there are some other ways to shoot yourself in the leg, because Windows.Forms does a lot of unmanaged code calls with possible side effects.

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

So, when could it possibly matter? And what are the rules of thumb about choosing the correct place to call the base method in these cases?

推荐答案

仅在该API的文档指定应调用base.SomeVirtualMethod时,才需要调用它.否则,应将其隐含为可选.要求您调用基本方法但未明确声明的API设计得不好.

You only need to call the base.SomeVirtualMethod when the documentation for that API specifies you should do so. Otherwise, it should be implied as optional. API's that require you to call the base method, but do not explicitly state so, are badly designed.

要求进行基本调用的原因是设计不良,原因是您永远无法期望某个人会重载您的方法,并且无法确定他们会调用该基本方法来执行任何必需的代码或关键代码.

The reason requiring a base call is poor design, is because you can never expect what someone overriding your method will do, and you cannot be certain they will call the base method to execute any required or critical code.

因此,简而言之,请参阅文档,否则,通常没有必要. .NET Framework是根据此类准则设计的,由于这些原因,大多数虚拟方法不需要调用基础.确实记录在案.

So in short, refer to the documentation, otherwise no it is usually not necessary. The .NET Framework was designed by such guidelines, most virtual methods don't require a call to the base for these reasons. The ones that do are documented.

感谢roken指出使用事件是调用基本虚拟方法的一个非常重要的原因.但是,我的反论点(并非总是如此)仍然适用,特别是如果您使用的第三方库或类不遵循.NET习惯用法和模式,则没有任何确定性.以这个例子为例.

Thanks to roken who pointed out a very important reason to call base virtual methods, is when using events. However, my counter argument that this is not always the case still applies, especially if you are using third party libraries or classes that don't follow the .NET idiom and patterns, there just isn't any certainty. Take this example.

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进行一次调用,而没有调用基址和订户.

If you run this example, you will get three invocations to Foo.OnLoad, DerivedFoo.OnLoad, and the event subscription dFoo.Load. If you comment out the call to base.OnLoad in DerivedFoo, you will now only get a single invocation to DerivedFoo.OnLoad, and the base and subscriber did not get called.

重点仍然在于它取决于文档.尚不能确定基本的虚拟方法实现会调用其订阅者.所以这应该很清楚.幸运的是,由于框架设计者的缘故,.NET Framework与.NET事件模型极为一致,但是我仍然不能承受太多压力,以至于总是要阅读该API的文档.

The point is still strong that its up to documentation. There is still no certainty that a base virtual method implementation invokes its subscribers. So that should be clear. Luckily the .NET Framework is extremely consistant to the .NET event model thanks to the framework designers, but I still cannot stress enough to always read the documentation for the API.

当您根本不处理事件,但处理诸如抽象基类之类的事件时,它会发挥很多作用.您如何知道是否为抽象类调用基本事件?抽象类是否提供默认实现,还是希望您提供默认实现?

It comes into play a lot when you're not dealing with events at all, but things like abstract base classes. How do you know whether to call a base event for an abstract class? Does the abstract class provide a default implementation, or does it expect you to provide it?

文档是为虚拟成员定义合同的最强大,最清晰的方法.这就是.NET框架设计人员团队通常为要交付的抽象类提供至少一个具体实现的原因之一.

Documentation is the strongest, clearest way to define a contract for a virtual member. This is one reason why the .NET framework designer team generally provides at least a single concrete implementation for an abstract class that gets shipped.

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

I think that Krzysztof Cwalina says it best in the framework design guidelines.

我遇到的一个常见问题是虚拟成员的文档是否应该说重写必须调用基本实现.答案是重写应该保留基类的契约.他们可以通过调用基本实现或其他方式来实现.成员很少会声称保留其合同(在替代中)的唯一方法是调用它.在很多情况下,调用基数可能是保存合同的最简单方法(文档应指出这一点),但这并不是绝对必要的.

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.

我完全同意.如果您覆盖了基本实现并决定不调用它,则应该提供相同的功能.

And I agree completely. In the case you override a base implementation and decide not to call it, you should provide the same functionality.

我希望这可以消除我在评论中的困惑.

I hope this clears up some confusion I had in the comments.

这篇关于C#-什么时候调用base.OnSomething?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆