天天看點

C#類中虛方法互相調用的潛在重載錯誤

當我們編寫基類虛方法時,需要注意一個問題,就是基類中虛方法的互相調用,有可能引起派生類重載時的潛在錯誤隐患。當然這個錯誤并不是C#語言設計的缺陷,而是一個不可避免的實作而已。當然如果我們是要編寫通用的組建基類,就需要注意一下了。

或許我們剛開始做OOP的時候,對于有沒有方法有沒有virtual根本不在乎,很多是時候我們都重寫了(rewrite)了基類方法。當然在需要确定重載(override)的時候,virtual關鍵字限定基類方法是不可少的。那麼是不時我們就可以把基類的方法都弄成virtual修飾的呢?這樣雖然在大多時候沒有問題,而其如果是自己重載自己的基類出問題的可能性也不大,可是如果是别人來繼承基類,那麼問題可能就來了。

C#類中虛方法互相調用的潛在重載錯誤

using System;

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

public class Base

C#類中虛方法互相調用的潛在重載錯誤

{

C#類中虛方法互相調用的潛在重載錯誤

    public virtual void Foo()

C#類中虛方法互相調用的潛在重載錯誤

    {

C#類中虛方法互相調用的潛在重載錯誤

        Console.WriteLine("Base::Foo");

C#類中虛方法互相調用的潛在重載錯誤

        this.Bar();

C#類中虛方法互相調用的潛在重載錯誤

    }

C#類中虛方法互相調用的潛在重載錯誤

    public virtual void Bar()

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

        Console.WriteLine("Base::Bar");

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

};

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

public class Derived : Base

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

    private Object obj;

C#類中虛方法互相調用的潛在重載錯誤

    public override void Foo()

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

        Console.WriteLine("Derived::Foo");

C#類中虛方法互相調用的潛在重載錯誤

        base.Foo();

C#類中虛方法互相調用的潛在重載錯誤

        obj = new Object();

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

    public override void Bar()

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

        Console.WriteLine(obj.ToString());

C#類中虛方法互相調用的潛在重載錯誤

        Console.WriteLine("Derived::Bar");

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

public class Test

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

    public static void Main()

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

        Derived b = new Derived();

C#類中虛方法互相調用的潛在重載錯誤

        b.Foo();

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

    編譯沒有錯誤,當然了,又不是在裡講C#文法

C#類中虛方法互相調用的潛在重載錯誤

。運作結果為:

   E:\Working\Doing>test

   Derived::Foo

   Base::Foo

C#類中虛方法互相調用的潛在重載錯誤

   Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.

     at Derived.Bar()

     at Derived.Foo()

     at Test.Main()

    問題代碼就是:

C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤
C#類中虛方法互相調用的潛在重載錯誤

    由于base.Foo()中的this.Bar()方法已被重載,是以實際執行的是Derived::Bar,而這個時候我的obj還沒有初始化呢。

當然修正這個bug也很容易,就是把Base::Bar變為非虛方法就可以了。由于C#可以靈活的設定virtual來控制方法是否需要重載,是以這類問題完全是由代碼的設計缺陷所引起的,而且如果由一個人來寫一般是不會設計出這樣的代碼的,可是如果基類和派生類由不同的人來寫,出這樣的錯誤的機會可能就會更大一些。

本文轉自部落格園鳥食軒的部落格,原文連結:http://www.cnblogs.com/birdshome/,如需轉載請自行聯系原部落客。