1. 程式人生 > >匿名方法和Lambda表達式

匿名方法和Lambda表達式

ted 數列 alc 垃圾回收 計算 com 例子 根據 etc

來自MSDN上的說法是這樣的

在 2.0 之前的 C# 版本中,聲明委托的唯一方法是使用命名方法。 C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表達式取代了匿名方法,作為編寫內聯代碼的首選方式。 有一種情況下,匿名方法提供了 Lambda 表達式中所沒有的功能。 您可使用匿名方法來忽略參數列表。 這意味著匿名方法可轉換為具有各種簽名的委托。 這對於 Lambda 表達式來說是不可能的。 有關 lambda 表達式的更多特定信息,請參見 Lambda 表達式(C# 編程指南)。

根據MSDN上的說法,我們知道先有委托,再有匿名方法,最後到Lanbda表達式。因此,在講解C#匿名方法之前,我們有必要說說C#委托這個東東。

委托是一個類型安全的對象,它指向程序中另一個以後會被調用的方法(或多個方法)。通俗的說,委托是一個可以引用方法的對象,當創建一個委托,也就創建一個引用方法的對象,進而就可以調用那個方法,即委托可以調用它所指的方法。

如何使用委托?
1、定義委托類型

[訪問修飾符]delegate 返回類型 委托名(形參);

2、聲明委托對象

委托名 委托實例名;

3、創建委托對象(確定與哪些方法進行綁定)

委托實例名=new 委托名(某個類的方法)

4、使用委托調用方法

委托實例名(實參)

委托註意事項:
1、委托和方法必須具有相同的參數。

2、委托可以調用多個方法,即一個委托對象可以維護一個可調用方法的列表而不是單獨的一個方法,稱為多路廣播(多播)。

3、使用+=和-=運算實現方法的增加和減少

下面我們通過一個小例子來講解下委托,其代碼如下(本事例通過計算器(+-*/)講解簡單的委托):

delegate int calculator(int x, int y); //委托類型
        static void Main(string[] args)
        {
            //創建委托對象(確定與哪些方法進行綁定),委托實例名=new 委托名(某個類的方法,本例與加法向綁定
            calculator MYAdd = new calculator(Adding);
            
//創建委托對象(確定與哪些方法進行綁定),委托實例名=new 委托名(某個類的方法,本例與減法向綁定 calculator MYMove = new calculator(Moveing); //創建委托對象(確定與哪些方法進行綁定),委托實例名=new 委托名(某個類的方法,本例與乘法向綁定 calculator MYMultiply = new calculator(Multiply); //創建委托對象(確定與哪些方法進行綁定),委托實例名=new 委托名(某個類的方法,本例與除法向綁定 calculator MYDivide = new calculator(Divide); //通過委托執行方法 int A = MYAdd(4, 4);//8 int B = MYMove(4, 4);//0 int C = MYMultiply(4, 4);//16 int D = MYDivide(4, 4);//1 } /// <summary> /// 加法 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public static int Adding(int x,int y) { return x + y; } /// <summary> /// 減法 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public static int Moveing(int x, int y) { return x - y; } /// <summary> /// 乘法 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public static int Multiply(int x, int y) { return x * y; } /// <summary> /// 除法 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public static int Divide(int x, int y) { return x / y; }

根據上述的事例,大家應該了解簡單委托的使用了。

那麽,我們更近一步,來說說泛型委托。泛型應該是大家比較熟悉的一種數據類型,泛型委托又是如何和泛型向結合的呢?

再講泛型委托之前,先說說微軟引入泛型的目的及使用泛型的好處。

  • 為什麽要有泛型
  •       假設你是一個方法的設計者,
  •       這個方法有一個傳入參數,有一個返回值。
  •       但你並不知道這個參數和返回值是什麽類型的,
  •       如果沒有泛型,你可能把參數和返回值的類型都設定為Object了
  •       那時,你心裏肯定在想:反正一切都是對象,一切的基類都是Object
  •       沒錯!你是對的!
  •       這個方法的消費者,會把他的對象傳進來(有可能會做一次裝箱操作)
  •       並且得到一個Object的返回值,他再把這個返回值強制類型轉化為他需要的類型
  •       那麽這個過程涉及到的裝箱拆箱會損耗系統的性能。
  •       那麽我們如何把損耗性能避免掉呢?
  •       有泛型之後就可以了!

微軟已經為我們事先定義好了三個泛型委托(Predicate,Action,Func),下面我們探討下這三個委托的不同。

1、Predicate 泛型委托定義如下:

public delegate bool Predicate<in T>(T obj);
這個委托表示的方法需要傳入一個T類型的參數,並且需要返回一個bool類型的返回值
代碼實例如下:
static void Main(string[] args)
        {
            //Predicate 泛型委托代表一類具有 一個T類型(通用類型)作為參數並返回BOOL類型的方法
            var B = new Predicate<int>(isbol);
            bool BB=isbol(1);//true
        }

       /// <summary>
        /// Predicate 泛型委托
       /// </summary>
       /// <typeparam name="?"></typeparam>
       /// <param name="x"></param>
       /// <returns></returns>
        public static bool isbol(int x)
        {
            return x > 0;
        }

2、Action委托定義如下:

public delegate void Action<T>(T obj,T obj2,...,obj16); --最多16個參數

 他代表了一類方法,可以有0個到16個輸入參數,輸入參數的類型是不確定的。此類方法不能有返回值,也就是返回VOID類型的方法。

代碼實例如下:

static void Main(string[] args)
        {
            //Action 他代表了一類方法,可以有0個到16個輸入參數,輸入參數的類型是不確定的。此類方法不能有返回值,也就是返回VOID類型的方法。
            var B = new Action<int,string,string>(Action_d);
            B(-1,"true","flase");
            Console.ReadKey();
        }

       /// <summary>
        /// Action 泛型委托
       /// </summary>
       /// <typeparam name="?"></typeparam>
       /// <param name="x"></param>
       /// <returns></returns>
        public static void Action_d(int x,string y,string z)
        {
            if (x > 0)
            {
                Console.WriteLine(y);
            }
            else
            {
                Console.WriteLine(z);
            }
        }

3、Func泛型委托 定義如下:

public delegate T Func<T>(T obj,T obj2,...,obj16); --最多16個參數

 為了彌補Action泛型委托,不能返回值的不足,.net提供了Func泛型委托,相同的是它也是最多0到16個輸入參數,參數類型由使用者確定,不同的是它規定要有一個返回值,返回值的類型也由使用者確定,說白了,就是ACtion委托沒有返回值,而FUNC委托具有了返回值,他們都是最多16個參數。

代碼實例如下:

static void Main(string[] args)
        {
            //Func 他代表了一類方法,可以有0個到16個輸入參數,輸入參數的類型是不確定的。此類方法有返回值。
            var B = new Func<int, string,string,string>(Func_d);//註意:<>中最後一個string代表輸出類型 
            Console.WriteLine(B(1,"True","False"));
            Console.ReadKey();
        }

       /// <summary>
        /// Predicate 泛型委托
       /// </summary>
       /// <typeparam name="?"></typeparam>
       /// <param name="x"></param>
       /// <returns></returns>
        public static string Func_d(int x,string y,string z)
        {
            if (x > 0)
            {
                return y;
            }
            else
            {
                return z;
            }
        }

學會了C#委托,那麽C#匿名方法就顯得很簡單了!下面和小夥伴們探討下C#匿名方法的使用!

還記得本篇上述的計算器吧!就是那個加減乘除委托。我們知道,我們在定義好委托後,還需要在定義加減乘數方法,C#引入匿名方法後,我們就不需要在單獨寫這些方法了,我們只需在匿名方法體內實現我們的業務邏輯即可!

delegate int calculator(int x, int y); //委托類型
        static void Main(string[] args)
        {
            //創建委托對象(確定與哪些方法進行綁定),委托實例名=new 委托名(某個類的方法,本例與加法向綁定
            calculator Adding =delegate( int x, int y)
            {
               return x+y;
            };

            calculator Moveing = delegate(int x, int y)
            {
                return x - y;
            };

            calculator Multiply = delegate(int x, int y)
            {
                return x * y;
            };

            calculator Divide = delegate(int x, int y)
            {
                return x / y;
            };
            Adding(4, 4);//8
            Moveing(4, 4);//0
            Multiply(4, 4);//16
            Divide(4, 4);//1
        }

講解到現在,想必大家對匿名方法有一定的了解了!

下面是參考MSDN上的一些資料如下:

通過使用匿名方法,由於您不必創建單獨的方法,因此減少了實例化委托所需的編碼系統開銷。

例如,如果創建方法所需的系統開銷是不必要的,則指定代碼塊(而不是委托)可能非常有用。 啟動新線程即是一個很好的示例。 無需為委托創建更多方法,線程類即可創建一個線程並且包含該線程執行的代碼。

C#
void StartThread()
{
    System.Threading.Thread t1 = new System.Threading.Thread
      (delegate()
            {
                System.Console.Write("Hello, ");
                System.Console.WriteLine("World!");
            });
    t1.Start();
}
備註

匿名方法的參數的範圍是“匿名方法塊”。

如果目標在塊外部,那麽,在匿名方法塊內使用跳轉語句(如 goto、break 或 continue)是錯誤的。 如果目標在塊內部,在匿名方法塊外部使用跳轉語句(如 gotobreakcontinue)也是錯誤的。

如果局部變量和參數的範圍包含匿名方法聲明,則該局部變量和參數稱為該匿名方法的“外部”變量。 例如,下面代碼段中的 n 即是一個外部變量:

C#
int n = 0;
Del d = delegate() { System.Console.WriteLine("Copy #:{0}", ++n); };

外部變量的引用n被認為是捕獲在創建委托時。 與本地變量不同,捕獲的變量的生存期內擴展,直到引用該匿名方法委托被垃圾回收。

匿名方法不能訪問外部範圍的 ref 或 out 參數。

在“匿名方法塊”中不能訪問任何不安全代碼。

在 is 運算符的左側不允許使用匿名方法。

好了,截止到現在,匿名方法講解完畢,如果需要更深入的了解匿名方法,可以找度娘哈!這裏僅僅只是簡單的介紹!

下一節,我們共同學習拉姆達表達式!lambda說: 一步一個腳印,學好C#基礎很重要!

匿名方法和Lambda表達式