C#基礎系列——委託實現簡單設計模式

前言:上一篇介紹了下多線程的相關知識:C#基礎系列——多線程的常見用法詳解,裏面就提到了委託變量。這篇簡單介紹下委託的使用。固然啦,園子裏面不少介紹委託的文章都會說道:委託和事件的概念就像一道坎,過了這個檻的人,以爲真是太容易了,而沒有過去的人每次見到委託和事件就以爲內心發慌。確實這東西就像最開始學C語言的指針同樣,使人有一種很糾結的感受,總以爲要調用一個方法直接調用就好了,爲啥非要定義一個委託時執行這個方法呢。其實在C#裏面不少的技術都是爲了重用和簡化代碼而生,委託也不例外,不少使用C#多態去實現的設計模式其實均可以使用委託的方式去改寫,能夠理解爲一種輕量級的設計模式吧。博主打算抽一篇專門分享下多態和委託實現設計模式的異同。這篇就先介紹簡單委託的使用。html

 

1、什麼是委託:C# 中的委託(Delegate)相似於 C 或 C++ 中函數的指針。用博主的話說,委託就是一種容許將方法名稱做爲參數傳遞的引用類型。它定義的是方法的類型,能夠說就是方法的抽象,那麼反過來講,方法能夠理解爲委託的實例,如public delegate void TestDelegate(string str);這種委託定義的就是全部參數類型爲string,沒有返回值的方法的一種抽象。設計模式

 

2、爲何要使用委託:記得博主剛開始作項目的時候看到委託的寫法就頭大,總以爲這是沒事找事,惟一的好處貌似就是代碼看上去很酷~~隨着工做的累積,發現項目中某些小的需求使用這種輕量級的委託來實現的時候確實能減小不少代碼量。多線程

 

3、委託的使用:ide

一、.Net Framework 裏面的委託類型:使用過委託的朋友可能注意到了C#裏面定義了兩種類型的委託變量,基本能知足咱們的通常需求。函數

(1)Action類型的委託:C#裏面定義Action委託用於抽象化那種沒有返回值的方法。將Action變量轉到定義可知它的最簡單形式:post

    // 摘要: 
    //     封裝一個方法,該方法不具備參數而且不返回值。
    [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
    public delegate void Action();

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

 

 

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

        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;
        }

調用:this

        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類型的委託用於處理有參數有返回值的方法。很少說,上代碼:spa

     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);

是否是同樣同樣的~~ 

 

二、自定義委託:

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基本沒有區別。

 

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

 

四、若是按照上面的方法去使用委託,那真的是要彆扭死人了,由於調用方法直接用方法名調用就行了,何須還要定義一個委託變量去調用,這不是將簡單問題複雜化麼。確實,上面只是爲了介紹委託而寫的代碼,實際項目中確定不會這麼用。其實委託在項目中通常用在將委託變量做爲參數傳遞或者函數回調。來看下面代碼:

   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();
        }
        
    }

獲得結果和上面相同:

這樣一比較是否是對委託的用法有點感受了呢~~若是你不怕麻煩,能夠在項目是用起來試試,相信你會有收穫~~

示例下載

相關文章
相關標籤/搜索