標籤:建構函式 第一個 編譯 返回 轉換 div where winform []
學習C#的WinForm編程需要涉及到事件(Event),學習事件又要涉及到委託(Delegate)。最開始事件和委託的文法相當困擾我,最後發現委託相當於類型,事件相當於執行個體。
delegate關鍵字定義了一個類,派生自System.MulticastDelegate類,而MulticaseDelegate類又派生自System.MulticaseDelegate類。儘管委託類在文法上很奇怪,但是不能否認委託仍然屬於物件導向的範疇,委託仍是一個類,只能說明C#增加了快捷使用委託的文法糖。
int x = 40;GetAString firstStringMethod = new GetAString(x.ToString);Console.WriteLine("String is {0}", firstStringMethod());
委託的執行個體是一個方法地址,既可以是執行個體方法,也可以是靜態方法。方法名稱後面帶圓括弧表示方法的調用,不帶圓括弧表示方法的地址。
關於 委託推斷(delegate inference)
委託推斷可以說是 C# 2.0 增加的一個文法糖。將一個方法的地址傳送給一個委託變數,編譯器會自動檢測委託變數的委託類型,然後根據委託類型建立委託執行個體,並把方法地址傳送給委託的建構函式。
GetAString firstStringMethod = new GetAString(x.ToString);
GetAString firstStringMethod = x.ToString;
說到這裡,委託的調用其實也是一個文法糖。委託的本質還是一個類,實現一個委託的執行個體也就是實現一個類的執行個體,只不過委託的執行個體只能調用經過定義後固定的方法。
GetAString firstStringMethod = new GetAString(x.ToString);firstStringMethod();
GetAString firstStringMethod = new GetAString(x.ToString);firstStringMethod.Invoke();
關於 泛型委派 Action<T> 和 Func<T>
先說泛型,C# 2.0 加入的泛型解決了兩個問題。
第一個是避免了“根據不同的參數類型,去定義不同的方法簽名”,即“泛型是個筐,啥都往裡裝”。泛型作為一個開放的資料類型,根據方法調用時的實參的值轉換成對應的方法簽名,這個過程在編譯時間就可以實現和錯誤修正。即,泛型實現了代碼中同一個方法多個入參實現的不同版本,在編譯時間可以根據需要分成多個入參類型的不同版本,假如是初級的編譯實現方法的話。
第二個是避免了實值型別和參考型別之間轉換時,所需要的裝箱(boxing)和拆箱(unboxing)的開銷。在我所設想的泛型編譯實現的方法中,最簡單的辦法莫過於根據泛型參數方法的調用,實現此方法在具體參數類型下的不同版本,即通過編譯器實現多個需要的版本,減少代碼編寫的工作量。
說到底,如果泛型沒有特別的編譯實現原理的話,就是一個協助開發人員減少代碼量的文法糖。不指定具體的參數類型,根據 where 關鍵字限定參數類型應符合的介面,在編譯時間根據方法的調用情況具體實現。這樣看來泛型和隱式類型一樣,即減少了開發人員的工作,又再編譯時間指定或推斷出了具體的參數類型,C#仍然是型別安全的強型別語言。
那麼 Action<T> 和 Func<T> 呢,在減少開發人員工作的道路上更近了一步。物件導向語言大多需要類型的聲明、類型的實現、類型的調用這三個步驟。委託作為一個類,也需要先定義再使用。那麼通過預定義的Action<T>和Func<T>委託,就免去了委託定義的步驟,同時通過泛型的實現,就囊括了常見的大部分委託。委託的定義本來就是指定參數的數量和各自類型,以及傳回值的類型,Action<T>和Func<T>一步實現了委託的定義和調用。
delegate double DoubleOp(double x);static void Main() { DoubleOp[] operations = { MathOperations.MultiplyByTwo, MathOperations.Square };}
static void Main() { Func<double, double>[] operations = { MathOperations.MultiplyByTwo, MathOperations.Square };}
關於Action<T>和Func<T>還有另一個問題。泛型委派可以實現隨用隨寫,不必提前定義。同時由於沒有定義委託名稱,各泛型型別之間沒有邏輯關聯。這樣的話使用起來,定義委託相比泛型委派,擁有全域定義的意義,類似於全域變數的意義,只不過由於委託定義了方法的簽名,委託一經使用就不可以再更改全域的定義。而泛型委派相比定義委託,調用時即可獲知委託變數的方法簽名,使用起來更直接,不必查詢委託的定義。如果沒有效能方面的考慮,當然我也考慮不到,我更願意使用泛型委派,即Action<T>和Func<T>。
static void ProcessAndDisplayNumber(DoubleOp action, double value) { double result = action(value); Console.WriteLine("Value is {0}, result of operation is {1}", value, result); }
static void ProcessAndDisplayNumber(Func<double, double> action, double value) { double result = action(value); Console.WriteLine("Value is {0}, result of operation is {1}", value, result);}
關於 多播委託
關於多播委託我暫時沒啥好說的。
參考資料:《Professional C# 4 and .NET 4》
C# 委託