1. 程式人生 > >C#基礎系列:委託實現簡單設計模式(1)

C#基礎系列:委託實現簡單設計模式(1)

前言:這篇簡單介紹下委託的使用。當然啦,園子裡面很多介紹委託的文章都會說道:委託和事件的概念就像一道坎,過了這個檻的人,覺得真是太容易了,而沒有過去的人每次見到委託和事件就覺得心裡發慌。確實這東西就像最開始學C語言的指標一樣,令人有一種很糾結的感覺,總覺得要呼叫一個方法直接呼叫就行了,為啥非要定義一個委託時執行這個方法呢。其實在C#裡面很多的技術都是為了重用和簡化程式碼而生,委託也不例外,很多使用C#多型去實現的設計模式其實都可以使用委託的方式去改寫,可以理解為一種輕量級的設計模式吧。博主打算抽一篇專門分享下多型和委託實現設計模式的異同。這篇就先介紹簡單委託的使用。

一、什麼是委託:C# 中的委託(Delegate)類似於 C 或 C++ 中函式的指標。用博主的話說,委託就是一種允許將方法名稱作為引數傳遞的引用型別。它定義的是方法的型別,可以說就是方法的抽象,那麼反過來說,方法可以理解為委託的例項

,如public delegate void TestDelegate(string str);這種委託定義的就是所有引數型別為string,沒有返回值的方法的一種抽象。

二、為什麼要使用委託:記得博主剛開始做專案的時候看到委託的寫法就頭大,總覺得這是沒事找事,唯一的好處貌似就是程式碼看上去很酷~~隨著工作的累積,發現專案中某些小的需求使用這種輕量級的委託來實現的時候確實能減少很多程式碼量。

三、委託的使用:

1、.Net Framework 裡面的委託型別:使用過委託的朋友可能注意到了C#裡面定義了兩種型別的委託變數,基本能滿足我們的一般需求。

(1)Action型別的委託:C#裡面定義Action委託用於抽象化那種沒有返回值的方法

。將Action變數轉到定義可知它的最簡單形式:

C#
1234 // 摘要: //封裝一個方法,該方法不具有引數並且不返回值。
[TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]publicdelegatevoidAction();

它定義是就是一種沒有返回值沒有引數的委託。同時Action還提供了16個泛型的委託,用於定義方法的傳入引數:

c#基礎系列

我們來看他們的使用方法,我們首先定義測試的方法:

C#
1234567891011121314151617181920212223242526 privatestaticvoidTest5(inta,intb,intc){//......}//無引數無返回值privatestaticvoidTest1(){Console.WriteLine("Func Test1, No Parameter");}//有引數無返回值privatestaticvoidTest2(stringstr){Console.WriteLine("Func Test2, Parameter is"+str);}//無引數有返回值privatestaticobjectTest3(){Console.WriteLine("Func Test3, Parameter");returnGuid.NewGuid().ToString();}//有引數有返回值privatestaticobjectTest4(stringstrRes){Console.WriteLine("Func Test4,  Parameter and Return Value");returnstrRes;}

呼叫:

C#
12345678910111213141516 staticvoidMain(string[]args){//1.無參無返回值方法varoAction1=newAction(Test1);oAction1.Invoke();//呼叫方式一oAction1();//呼叫方式二//2.有參無返回值varoAction2=newAction<int,int,int>(Test5);oAction2.Invoke(1,2,3);oAction2(1,2,3);//匿名方法的呼叫varoAction3=newAction<int,int,int>((a,b,c)=>{//......});oAction3.Invoke(1,2,3);}

(2)Func型別的委託:還記得Linq裡面的擴充套件方法Where()、Select()等方法的引數嗎。public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)。這裡的引數就是一個Func型別的委託。C#裡面Func型別的委託用於處理有引數有返回值的方法。不多說,上程式碼:

C#
1234567 staticvoidMain(string[]args){varoFunc1=newFunc<object>(Test3);varofuncRes1=oFunc1.Invoke();varoFunc2=newFunc<string,object>(Test4);oFunc2("a");}

知道了Func的方法就可以推想到我們神奇的lamada表示式了,其實lamada表示式就是一個匿名的委託。

C#
12 varlstTest=newList<string>();varlstRes=lstTest.Where(x=>x.Contains("_"));

這個Where裡面的lamada表示式我們把他拆解:

C#
1234 privatestaticboolTestWhere(stringx){returnx.Contains("_");}
C#
12 varoFunc=newFunc<string,bool>(TestWhere);lstRes=lstTest.Where(oFunc);

是不是一樣一樣的~~

2、自定義委託:

C#
1 publicdelegatevoidTestDelegate(stringstr);

其實很多人應該都自己寫過Action、Func型別的委託。其實自己定義一個泛型委託也很簡單:

C#
12 publicdelegatevoidMyAction<inT>();publicdelegateTResult MyFunc<inT,outTResult>(Targ);

其實使用起來和系統的Action和Func基本沒有區別。

3、委託的合併和拆解就放在事件裡面分享了。這篇且過之。。。

4、如果按照上面的方法去使用委託,那真的是要彆扭死人了,因為呼叫方法直接用方法名呼叫就好了,何必還要定義一個委託變數去呼叫,這不是將簡單問題複雜化麼。確實,上面只是為了介紹委託而寫的程式碼,實際專案中肯定不會這麼用。其實委託在專案中一般用在將委託變數作為引數傳遞或者函式回撥。來看下面程式碼:

C#
123456789101112131415161718192021222324252627282930313233343536373839404142 classProgram{staticvoidMain(string[]args){Person strHelper=newPerson();stringr1=strHelper.ProcessFunc("中國人","你好",newMyDelegate(strHelper.ChineseSayHello));stringr2=strHelper.ProcessFunc("English","Hello",newMyDelegate(strHelper.EnglishSayHello));stringr3=strHelper.ProcessFunc("Japanese","こんにちは",newMyDelegate(strHelper.JapaneseSayHello));Console.WriteLine(r1);Console.WriteLine(r2);Console.WriteLine(r3);Console.ReadKey();}}publicdelegatestringMyDelegate(strings1,strings2);publicclassPerson{publicstringProcessFunc(strings1,strings2,MyDelegate process){returnprocess(s1,s2);}publicstringChineseSayHello(strings1,strings2){returns1+","+s2;}publicstringEnglishSayHello(strings1,strings2){returns1+","+s2;}publicstringJapaneseSayHello(strings1,strings2){returns1+","+s2;}}

得到結果:

c#基礎系列

public string ProcessFunc(string s1, string s2, MyDelegate process)裡面定義了一個回撥函式,可以將任意一個符合這個委託的方法傳遞進去,得到想對應的結果。細看這種設計是不是和工廠設計模式十分相似,我簡單構造了個工廠:

C#
12345678910111213141516171819202122232425262728293031323334353637383940414243