咱們都知道,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