C#構造函數在繼承時必需要求與父類型構造函數入參相同怎麼辦?

摘要

咱們都知道,C#中,在類型繼承時,因爲構造子類必須先構造其父類型的內容,所以,必須子類型的構造函數中調用父類型的構造函數(無參數的不須要顯式聲明)。函數

可是每每咱們會出現,子類型自己的構造函數大於或小於父類型構造函數的狀況,那咱們應該怎麼辦呢?this

 


 

簡單情景:父類型須要兩個參數,而子類型只需一個參數

好比咱們有一個專門用來計算兩個數相乘的類型:spa

class Multi
{
    public int Result { get; private set; }

    public Multi(int i,int j)
    {
        this.Result = i * j;
    }
}

 

而後,乘法中有一個特殊的狀況就是平方,若是咱們再創建一個類型用於直接計算平方的話,那構造函數只須要一個值就好了。code

可是因爲咱們繼承的父類型的構造函數有兩個參數,全部咱們要使用一些特殊的語法來標明,子類如何調用父類型的構造函數:對象

class Squ : Multi
{
    public Squ(int i)
        : base(i, i) //經過這行代碼,表示在new Squ(i)時,執行new Multi(i,i);
    {

    }
}

 

 


 

複雜情景:子類型構造時的參數,不能直接用於父類型的構建,須要通過很是複雜的過程才能獲得父類型的構建參數

這是一種極少數狀況下會遇到狀況。blog

可是遇到之後,若是經驗不足,你們也會不知道如何下手處理。繼承

咱們繼續使用上面的Multi做爲父類型,實現一個子類,用於「計算一元二次方程中的一正整數解」的子類出來。內存

 

——呃,這怎麼可能。。。。。get

想必你們的第一反應是這樣的。io

 

那咱們就來仔細分析一下,一元二次方程的求根公式是 ( -b ± √(b * b - 4 * a * c) / (2 * a)

除一個數,其實就是乘以它的相反數嘛。

因而這就變成了構建一個Multi對象,第一個參數是-b ± √(b * b - 4 * a * c),第二個參數是 1 / (2 * a)嘛

可是咱們的命題是「正整數解」也就是說,咱們還要加入一些判斷邏輯在裏面,在僅僅的一行base(xxx,yyy)中間,咱們有辦法實現這麼多代碼嗎?

 

答案很簡單:固然沒辦法在base中寫入這麼多代碼!最糟糕的是,咱們還只能在base裏面寫這些複雜的邏輯。

 

————那。。。。該如什麼時候好呢?

 

答案就是「靜態方法」,靜態函數在類型第一次被訪問時就已經初始化好了,那麼在實例化時,更不用,早就存在內存中了。

經過靜態方法,以及ref或out關鍵字,咱們能夠以靜態函數做爲媒介,建立出一個徹底符合要求的base語句來。

class MyFunc : Multi
{
    private static int CtorExt(int a, int b, int c, ref int j)
    {
        var d = b * b - 4 * a * c; //求delta,與0的比較不在此示例中演示
        var sd = Math.Sqrt(d);     //求平方根
        var i1 = -b + sd;          //計算兩個根的分子
        var i2 = -b - sd;
        j = 2 * a;
        //判斷與j的符號性,當符號相同時(正數)返回
        //註明:返回整數形式僅示例做用
        if (i1 > 0 && j > 0) return (int)i1;
        if (i1 < 0 && j < 0) return (int)i1;
        if (i2 > 0 && j > 0) return (int)i2;
        if (i2 < 0 && j < 0) return (int)i2;
        throw new ApplicationException("無正數解");
    }

    public MyFunc(int a, int b, int c, int j)
        : base(CtorExt(a, b, c, ref j), j)
    {

    }
}

 

經過上面這種複雜的方式,咱們在子類的構造函數中,執行了CtroExt這個靜態方法,這個方法返回了用於構建父類型的第一個參數i,還經過ref關鍵字,獲得了用於構建父類型的第二個參數j,因而base語句獲得了完美的使用。

可是美中不足的是,子類的構建函數多了一個j做爲入參,可是外部調用的時候,這個j毫無心義(由於值是最終會被CtorExt所替換,爲了保證一個好的調用環境,咱們應該將這個構造函數設爲私有,再爲新增一個符合要求的構造函數

class MyFunc : Multi
{
    private static int CtorExt(int a, int b, int c, ref int j)
    {
        var d = b * b - 4 * a * c; //求delta,與0的比較不在此示例中演示
        var sd = Math.Sqrt(d);     //求平方根
        var i1 = -b + sd;          //計算兩個根的分子
        var i2 = -b - sd;
        j = 2 * a;
        //判斷與j的符號性,當符號相同時(正數)返回
        //註明:返回整數形式僅示例做用
        if (i1 > 0 && j > 0) return (int)i1;
        if (i1 < 0 && j < 0) return (int)i1;
        if (i2 > 0 && j > 0) return (int)i2;
        if (i2 < 0 && j < 0) return (int)i2;
        throw new ApplicationException("無正數解");
    }

    private MyFunc(int a, int b, int c, int j)
        : base(CtorExt(a, b, c, ref j), j)
    {

    }
    public MyFunc(int a, int b, int c)
        : this(a, b, c, 0) //由於j最終會被替代,所以這裏隨便寫什麼值都行
    {

    }
}

 

 


 

總結:

一、這種解決方案也是「封裝」思想的體現,將一個複雜的方法封裝,並直接調用,能夠獲得咱們想要的結構,而不關心實現過程。

二、靜態函數是能夠在造構函數剛發生時使用的,由於它「早已準備好了」

三、ref關鍵字在這裏很是重要

四、這是一種閱讀性不是很是好的編方式,不到萬不得已時,儘量不要使用。

 

 

原文地址 http://www.zizhusoft.com/note/show.aspx?id=a8240ee2-eeeb-4cb3-bc7e-00aec29476f2

相關文章
相關標籤/搜索