十七 关于委托
先看委托。 然后事件 當然可恥的直接用了書的源碼。
首先.. 委托就和js中得回調一樣,別人都用c舉例...本人只能用js舉例。。。。 ╮(╯▽╰)╭
function a(func) {var el= document.body;func(el) } function b(el) { do something.. } a(b);委托也是這樣.. 不過要麻煩很多.
internal delegate void Feedback(Int32 value); 先定義public static void Main()
{
Counter(1, 3, new Feedback(FeedbackToConsole)); //這是調用... 同樣是將方法傳入
//Counter(1, 3, Program.FeedbackToConsole); //這樣也是可以的
}
private static void Counter(Int32 from, Int32 to, Feedback fb)
{
for (Int32 val = from; val <= to; val++)
{
if (fb != null)
fb(val);
}
}
private static void FeedbackToConsole(Int32 value)
{
Console.WriteLine("Item=" + value);
}
關于協變 逆變
協變 就是委托返回的類型是派生類
逆變 就是返回基類..
當然 他們只能針對值類型
internal delegate?object?Feedback(Int32 value);?
你綁定的方法可以是 string aaa(int i);
不過關于協變逆變的性能以后再討論
前面調用的都是靜態方法,這里傳了一個實例,當然只是把棧中得地址傳了過去
private static void InstanceDelegateDemo(){
Program p = new Program();
Counter(1, 3, new Feedback(p.FeedbackToFile)); //這里傳遞的是引用..
Console.WriteLine();
}
關于寫法. 委托從1.0到現在寫法有一些變化..
internal delegate void Feedback(Int32 value);public static void Main() {
Counter(1, 3, new Feedback(FeedbackToMsgBox)); 1.0 Counter(1, 3, delegate(int a) 2.0 { //匿名方法 //你不必單獨創建方法 就像上面的FeedbackToMsgBox,當然這玩意兒得建立在你只在這里使用 //感覺上就像閉包. 當然前提是他得引用上下文.. //當然簡便代碼是很重要的,很多時候調用方法需要傳入一個委托, 沒有他你就麻煩了。。 //也有缺點。 畢竟像過多外部參數 維護起來 啊哈 });
Counter(1,3, a => a++); 3.5
//貌似生成的代碼是一個匿名方法 攤手..
//適當的使用委托(包括 匿名方法,lamb), 能讓代碼更優美~~~~~~~~~
} private static void Counter(Int32 from, Int32 to, Feedback fb){}
關于他里面干了什么?
首先看IL.. 雖然看的惱火
internal delegate void Feedback(Int32 value);
.class auto ansi sealed nested assembly Feedbackextends [mscorlib]System.MulticastDelegate
{
.method public hidebysig specialname rtspecialname instance void .ctor(object 'object', native int 'method') runtime managed
{
}
.method public hidebysig newslot virtual instance class [mscorlib]System.IAsyncResult BeginInvoke(int32 'value', class [mscorlib]System.AsyncCallback callback, object 'object') runtime managed
{
}
.method public hidebysig newslot virtual instance void EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
{
}
.method public hidebysig newslot virtual instance void Invoke(int32 'value') runtime managed
{
}
}
繼承自?System.MulticastDelegate
第一個是一個構造
所有委托都有構造器,參數一個是 object 一個是int 開始我以為是傳得參數,畢竟委托的參數也是int,后來重新寫了一個 string參數的委托,發現構造的參數還是int。 憂郁。Object是引用對象(引發裝箱拆箱?),如果傳入的是靜態方法 Object 會是null
Int 據書上說是 標識了方法的一個特殊值...
然后 在構造器內部 object 和 Int 分別保存在_target _methouPtr
然后一個和原型一樣的方法
這玩意就是調用原方法的方法.. 委托都會隱式的調用他.然后就是三個變量
之前上面提到了
_target //如果你傳入的不是靜態方法, 那這個就存放你傳進來的方法所屬的類_methouPtr //只是一個整數值,標示回調的方法
_invocationList //數組. 通常是null 只有在委托鏈的時候
關于委托鏈
Console.WriteLine("----- Chain Delegate Demo 1 -----");Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToMsgBox);
Feedback fb3 = new Feedback(p.FeedbackToFile);
Feedback fbChain = null;
fbChain = (Feedback)Delegate.Combine(fbChain, fb1);
fbChain = (Feedback)Delegate.Combine(fbChain, fb2);
fbChain = (Feedback)Delegate.Combine(fbChain, fb3);
Counter(1, 2, fbChain);
Console.WriteLine();
fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox));
Counter(1, 2, fbChain);
書上的例子很明確了
在添加的時候
_invocationList [0,1,2] 分別代表的3個委托,所以在 Counter執行的時候 會分別調用那3個委托
同樣 也提供了Remove 刪除不用的
當然也有簡便方法
fbChain += fb1;
fbChain += fb2;
fbChain += fb3;
fbChain.GetInvocationList(); 返回Delegate[] over~
泛型委托
internal delegate void Feedback(T value); //只是一個T~ 其他不變
關于泛型這里就不贅述了 會在之后的寫 到時候再反過來加鏈接吧
ok 談談委托的使用
其實都知道 委托在很多程度上可以用 接口來代替, 只是每次都弄個類 搞個接口 確實比較繁瑣
委托給人的感覺就是不知道使用者要干什么,如果上下文清楚 個人感覺使用接口要好一點(當然,這對我來說只是規范問題)
其實這里還差一段代碼... 就是測試 委托 和 接口.. 在處理相同的時候的效率問題本人思來想去 還是覺得自己的測試方法不太好, 暫時擱置一下吧. 想到了再說
ok 之前是我的觀點.
還有一種觀點就是,這些性能損失在實際代碼中是微乎其微的.
而是應該在性能和可讀性,可維護性上找到一個平衡點
不可否認 lamb表達式的正確使用確實讓代碼易懂和優美。
a.Select(lamb).Where(lamb)
.OrderBy(lamb)
.ToList();
當你使用它的時候有些東西需要注意
1. 這一連串的方法,他當時不會執行,只會在你調用的時候才會執行~
2. 他是循環執行的 第一個元素 select - where - select - orderBy - 第二個元素 重復..
3. 就是他得延遲性(這玩意兒..我沒有研究)
有興趣的可以去看看 姐夫趙的 從.NET中委托寫法的演變談開去(下):性能相關
特別是在使用官方提供的方法的時候,lamb的優勢極其明顯
當然也有缺點 比如調試,lamb表達式無法調試,所以建議在lamb表達式中不要有復雜邏輯,要不然調試起來夠你折騰
over
轉載于:https://www.cnblogs.com/CallMeTommy/archive/2011/08/28/2148662.html
總結
- 上一篇: OpenGL和D3D的区别
- 下一篇: IT技术文章示例(附源码)