1. 程式人生 > >C# 匿名方法

C# 匿名方法

每次寫部落格,第一句話都是這樣的:程式設計師很苦逼,除了會寫程式,還得會寫部落格!當然,希望將來的一天,某位老闆看到此部落格,給你的程式設計師職工加點薪資吧!因為程式設計師的世界除了苦逼就是沉默。我眼中的程式設計師大多都不愛說話,默默承受著程式設計的巨大壓力,除了技術上的交流外,他們不願意也不擅長和別人交流,更不樂意任何人走進他們的內心,他們常常一個人宅在家中!

廢話說多了,咱進入正題:

上一節我們談到了匿名變數,本節我們學習匿名方法。

來自MSDN上的說法是這樣的

在 2.0 之前的 C# 版本中,宣告委託的唯一方法是使用命名方法。  C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表示式取代了匿名方法,作為編寫內聯程式碼的首選方式。  有一種情況下,匿名方法提供了 Lambda 表示式中所沒有的功能。  您可使用匿名方法來忽略引數列表。  這意味著匿名方法可轉換為具有各種簽名的委託。  這對於 Lambda 表示式來說是不可能的。  

根據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();
}
備註

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

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

如果區域性變數和引數的範圍包含匿名方法宣告,則該區域性變數和引數稱為該匿名方法的“外部”變數。  例如,下面程式碼段中的 n 即是一個外部變數:  

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

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

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

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

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