前言:這篇簡單介紹下委托的使用。當然啦,園子里面很多介紹委托的文章都會說道:委托和事件的概念就像一道坎,過了這個檻的人,覺得真是太容易了,而沒有過去的人每次見到委托和事件就覺得心里發慌。確實這東西就像最開始學C語言的指針一樣,令人有一種很糾結的感覺,總覺得要調用一個方法直接調用就行了,為啥非要定義一個委托時執行這個方法呢。其實在C#里面很多的技術都是為了重用和簡化代碼而生,委托也不例外,很多使用C#多態去實現的設計模式其實都可以使用委托的方式去改寫,可以理解為一種輕量級的設計模式吧。博主打算抽一篇專門分享下多態和委托實現設計模式的異同。這篇就先介紹簡單委托的使用。
一、什么是委托:C# 中的委托(Delegate)類似於 C 或 C++ 中函數的指針。用博主的話說,委托就是一種允許將方法名稱作為參數傳遞的引用類型。它定義的是方法的類型,可以說就是方法的抽象,那么反過來說,方法可以理解為委托的實例,如public delegate void TestDelegate(string str);這種委托定義的就是所有參數類型為string,沒有返回值的方法的一種抽象。
二、為什么要使用委托:記得博主剛開始做項目的時候看到委托的寫法就頭大,總覺得這是沒事找事,唯一的好處貌似就是代碼看上去很酷~~隨着工作的累積,發現項目中某些小的需求使用這種輕量級的委托來實現的時候確實能減少很多代碼量。
三、委托的使用:
1、.Net Framework 里面的委托類型:使用過委托的朋友可能注意到了C#里面定義了兩種類型的委托變量,基本能滿足我們的一般需求。
(1)Action類型的委托:C#里面定義Action委托用於抽象化那種沒有返回值的方法。將Action變量轉到定義可知它的最簡單形式:
1
2
3
4
|
// 摘要:
//封裝一個方法,該方法不具有參數並且不返回值。
[TypeForwardedFrom(
"System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089"
)]
public
delegate
void
Action();
|
它定義是就是一種沒有返回值沒有參數的委托。同時Action還提供了16個泛型的委托,用於定義方法的傳入參數:
我們來看他們的使用方法,我們首先定義測試的方法:
private static void Test5(int a, int b, int c) { //...... } //無參數無返回值 private static void Test1() { Console.WriteLine("Func Test1, No Parameter"); } //有參數無返回值 private static void Test2(string str) { Console.WriteLine("Func Test2, Parameter is" + str); } //無參數有返回值 private static object Test3() { Console.WriteLine("Func Test3, Parameter"); return Guid.NewGuid().ToString(); } //有參數有返回值 private static object Test4(string strRes) { Console.WriteLine("Func Test4, Parameter and Return Value"); return strRes; }
調用:
static void Main(string[] args) { //1.無參無返回值方法 var oAction1 = new Action(Test1); oAction1.Invoke();//調用方式一 oAction1();//調用方式二 //2.有參無返回值 var oAction2 = new Action<int, int, int>(Test5); oAction2.Invoke(1, 2, 3); oAction2(1, 2, 3); //匿名方法的調用 var oAction3 = new Action<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類型的委托用於處理有參數有返回值的方法。不多說,上代碼:
static void Main(string[] args) { var oFunc1 = new Func<object>(Test3); var ofuncRes1 = oFunc1.Invoke(); var oFunc2 = new Func<string, object>(Test4); oFunc2("a"); }
知道了Func的方法就可以推想到我們神奇的lamada表達式了,其實lamada表達式就是一個匿名的委托。
var lstTest = new List<string>(); var lstRes = lstTest.Where(x => x.Contains("_"));
這個Where里面的lamada表達式我們把他拆解:
private static bool TestWhere(string x) { return x.Contains("_"); }
var oFunc = new Func<string, bool>(TestWhere); lstRes = lstTest.Where(oFunc);
是不是一樣一樣的~~
2、自定義委托:
public delegate void TestDelegate(string str);
其實很多人應該都自己寫過Action、Func類型的委托。其實自己定義一個泛型委托也很簡單:
public delegate void MyAction<in T>(); public delegate TResult MyFunc<in T, out TResult>(T arg);
其實使用起來和系統的Action和Func基本沒有區別。
3、委托的合並和拆解就放在事件里面分享了。這篇且過之。。。
4、如果按照上面的方法去使用委托,那真的是要別扭死人了,因為調用方法直接用方法名調用就好了,何必還要定義一個委托變量去調用,這不是將簡單問題復雜化么。確實,上面只是為了介紹委托而寫的代碼,實際項目中肯定不會這么用。其實委托在項目中一般用在將委托變量作為參數傳遞或者函數回調。來看下面代碼:
class Program { static void Main(string[] args) { Person strHelper = new Person(); string r1 = strHelper.ProcessFunc("中國人", "你好", new MyDelegate(strHelper.ChineseSayHello)); string r2 = strHelper.ProcessFunc("English", "Hello", new MyDelegate(strHelper.EnglishSayHello)); string r3 = strHelper.ProcessFunc("Japanese", "こんにちは", new MyDelegate(strHelper.JapaneseSayHello)); Console.WriteLine(r1); Console.WriteLine(r2); Console.WriteLine(r3); Console.ReadKey(); } } public delegate string MyDelegate(string s1, string s2); public class Person { public string ProcessFunc(string s1, string s2, MyDelegate process) { return process(s1, s2); } public string ChineseSayHello(string s1, string s2) { return s1 +","+ s2; } public string EnglishSayHello(string s1, string s2) { return s1 + "," + s2; } public string JapaneseSayHello(string s1, string s2) { return s1 +","+ s2; } }
得到結果:
public string ProcessFunc(string s1, string s2, MyDelegate process)里面定義了一個回調函數,可以將任意一個符合這個委托的方法傳遞進去,得到想對應的結果。細看這種設計是不是和工廠設計模式十分相似,我簡單構造了個工廠:
public class Person { public virtual string SayHello(string s2) { return s2; } } public class Chinese : Person { public override string SayHello(string s2) { return "中國人," + s2; } } public class English : Person { public override string SayHello(string s2) { return "English," + s2; } } public class Japanese : Person { public override string SayHello(string s2) { return "Japanese," + s2; } } //Main函數里面調用 class Program { static void Main(string[] args) { var r1 = GetPerson("你好").SayHello("你好"); var r2 = GetPerson("Hello").SayHello("Hello"); var r3 = GetPerson("こんにちは").SayHello("こんにちは"); Console.WriteLine(r1); Console.WriteLine(r2); Console.WriteLine(r3); Console.ReadKey(); } public static Person GetPerson(string strType) { if (strType == "你好") return new Chinese(); else if (strType == "Hello") return new English(); else return new Japanese(); } }
得到結果和上面相同:
這樣一比較是不是對委托的用法有點感覺了呢~~如果你不怕麻煩,可以在項目是用起來試試,相信你會有收獲~~