C#类中虚方法相互调用的潜在重载错误

当我们编写基类虚方法时,需要注意一个问题,就是基类中虚方法的相互调用,有可能引起派生类重载时的潜在错误隐患。当然这个错误并不是C#语言设计的缺陷,而是一个不可避免的实现而已。当然如果我们是要编写通用的组建基类,就需要注意一下了。

    或许我们刚开始做OOP的时候,对于有没有方法有没有virtual根本不在乎,很多是时候我们都重写了(rewrite)了基类方法。当然在需要确定重载(override)的时候,virtual关键字限定基类方法是不可少的。那么是不时我们就可以把基类的方法都弄成virtual修饰的呢?这样虽然在大多时候没有问题,而其如果是自己重载自己的基类出问题的可能性也不大,可是如果是别人来继承基类,那么问题可能就来了。

    当我们重载不确切的基类是,最好的习惯是调用以下 base的同名方法,这个在控件开发时用的更加普遍。可是这个时候,如果基类之间存在虚方法调用了别的被重载的虚方法,潜在错误就出来了。看下面示例(由 xingd提供,我修改):
None.gif using System;
None.gif
None.gif public  class Base
ExpandedBlockStart.gif{
InBlock.gif     public  virtual  void Foo()
ExpandedSubBlockStart.gif    {
InBlock.gif        Console.WriteLine("Base::Foo");
InBlock.gif         this.Bar();
ExpandedSubBlockEnd.gif    }
InBlock.gif     public  virtual  void Bar()
ExpandedSubBlockStart.gif    {
InBlock.gif        Console.WriteLine("Base::Bar");
ExpandedSubBlockEnd.gif    }
ExpandedBlockEnd.gif};
None.gif
None.gif public  class Derived : Base
ExpandedBlockStart.gif{
InBlock.gif     private Object obj;
InBlock.gif     public  override  void Foo()
ExpandedSubBlockStart.gif    {
InBlock.gif        Console.WriteLine("Derived::Foo");
InBlock.gif         base.Foo();
InBlock.gif        obj =  new Object();
InBlock.gif         this.Bar();
ExpandedSubBlockEnd.gif    }
InBlock.gif     public  override  void Bar()
ExpandedSubBlockStart.gif    {
InBlock.gif        Console.WriteLine(obj.ToString());
InBlock.gif        Console.WriteLine("Derived::Bar");
ExpandedSubBlockEnd.gif    }
ExpandedBlockEnd.gif};
None.gif
None.gif public  class Test
ExpandedBlockStart.gif{
InBlock.gif     public  static  void Main()
ExpandedSubBlockStart.gif    {
InBlock.gif        Derived b =  new Derived();
InBlock.gif        b.Foo();
ExpandedSubBlockEnd.gif    }
ExpandedBlockEnd.gif};

    编译没有错误,当然了,又不是在里讲C#语法 emdgust.gif。运行结果为:
   E:\Working\Doing>test
   Derived::Foo
   Base::Foo
None.gif
   Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
     at Derived.Bar()
     at Derived.Foo()
     at Test.Main()

    问题代码就是:
None.gif        Console.WriteLine("Derived::Foo");
None.gif         base.Foo();
None.gif        obj =  new Object();
None.gif         this.Bar();
    
    由于 base.Foo()中的 this.Bar()方法已被重载,所以实际执行的是Derived::Bar,而这个时候我的obj还没有初始化呢。

    当然修正这个bug也很容易,就是把Base::Bar变为非虚方法就可以了。由于C#可以灵活的设置virtual来控制方法是否需要重载,所以这类问题完全是由代码的设计缺陷所引起的,而且如果由一个人来写一般是不会设计出这样的代码的,可是如果基类和派生类由不同的人来写,出这样的错误的机会可能就会更大一些。


本文转自博客园鸟食轩的博客,原文链接:http://www.cnblogs.com/birdshome/,如需转载请自行联系原博主。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值