天天看點

C# 委托 Lambda Linq Dynamic 總結

1,C# 委托

委托:   是一種引用方法的類型。一旦為委托配置設定了方法,委托将與該方法具有完全相同的行為。委托方法的使用可以像其他任何方法一樣,具有參數和傳回值

  将方法作為參數進行引用的能力使委托成為定義回調方法的理想選擇。例如,可以向排序算法傳遞對比較兩個對象的方法的引用。分離比較代碼使得可以采用更通用的方式編寫算法。

委托概述

          委托具有以下特點:

           委托類似于 C++ 函數指針,但它是類型安全的。

           委托允許将方法作為參數進行傳遞。

           委托可用于定義回調方法。

           委托可以連結在一起;例如,可以對一個事件調用多個方法。

           方法不需要與委托簽名精确比對。

           C# 2.0 版引入了匿名方法的概念,此類方法允許将代碼塊作為參數傳遞,以代替單獨定義的方法。 

C# 1.0聲明委托

          public delegate void Del<T>(T item);

          public void Notify(int i) { }

使用委托

          Del<int> d1 = new Del<int>(Notify);

C#2.0使用委托

         Del<int> d2 = Notify;

C#3.0以上版本可以使用Lambda表達式來取代C#2.0裡面的匿名委托

         Action<int> d3 = s => s;

下面分别做下比較

public class DelegateExample
   {
       //命名委托
       delegate void Del(int i, double j);
       //匿名委托
       delegate void Printer(string s);
       public static void Run()
       {
           //C#2.0之前的命名方法委托
           Del dl = MultiplyNumbers;
           for (int i = 0; i < 5; i++)
           {
               dl(i,2);
           }
           //C#2.0引入了匿名方法--匿名方法的參數的範圍是匿名方法塊
           Printer print = delegate(string p) { Console.WriteLine(p); };
           //使用匿名委托
           print("匿名函數");
           //使用命名方法的委托
           print = new Printer(DoWork);
           print("命名方法委托");
 
           // C# 3.0 及更高版本中,Lambda 表達式取代了匿名方法
           //上面的例子可以改為Action有參數但無傳回值的,如果是有傳回值的用Func<>
           Action<string> funcprint = s => Console.WriteLine(s);
           funcprint("Lambda表達式");
           Console.ReadKey();
       }
       static void MultiplyNumbers(int i, double j)
       {
           Console.WriteLine("i * j  = " + i * j);
       }
       static void DoWork(string p)
       {
           Console.WriteLine(p);
       }
   }

           

2,Lambda

“Lambda 表達式”是一個匿名函數,它可以包含表達式和語句,并且可用于建立委托或表達式樹類型。 所有 Lambda 表達式都使用 Lambda 運算符 =>,該運算符讀為“goes to”。 該 Lambda 運算符的左邊是輸入參數(如果有),右邊包含表達式或語句塊。 Lambda 表達式 x => x * x 讀作“x goes to x times x”。可以将此表達式配置設定給委托類型.
delegate int del(int i);
       static void Main(string[] args)
       {
           del myDelegate = x => x * x;
           int j = myDelegate(5); //j = 25
       }

           
建立表達式樹類型:
using System.Linq.Expressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<del> myET = x => x * x;
        }
    }
}

           
Lambda 的一般規則如下:

        Lambda 包含的參數數量必須與委托類型包含的參數數量相同。

        Lambda 中的每個輸入參數必須都能夠隐式轉換為其對應的委托參數。

        Lambda 的傳回值(如果有)必須能夠隐式轉換為委托的傳回類型。

        Lambda 表達式本身沒有類型,因為正常類型系統沒有“Lambda 表達式”這一内部概念。但是,有時會不正式地論及 Lambda 表達式的“類型”。 在這些情況下,類型是指委托類型或 Lambda 表達式所轉換為的 Expression 類型。

//此處顯示了一個Lambda标準查詢運算
      int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
      //篩選出滿足該條件的唯一進制素
      int oddNumbers = numbers.Single(n => n  == 0);
      Console.WriteLine(oddNumbers.ToString());
      //隻要滿足條件就會傳回元素
      var fielNumbers = numbers.TakeWhile(n => n < 8);
      foreach (var item in fielNumbers)
      {
          Console.WriteLine(item.ToString());
      }
           
C# 2.0規範中提到的匿名方法規範同樣适用于Lambda表達式。Lambda表達式是匿名方法在功能行上的超集,提供了下列附加的功能:      

l         Lambda表達式允許省略參數類型并對其進行推斷,而匿名方法要求參數類型必須顯式地聲明。

l         Lambda表達式體可以是表達式或語句塊,而匿名方法體隻能是語句塊。

l         在類型參數推導和方法重載抉擇時,Lambda表達式可以被作為參數傳遞。

l         以一個表達式作為表達式體的Lambda表達式可以被轉換為表達式樹。

表達式樹類型:表達式樹表示樹狀資料結構的代碼,樹狀結構中的每個節點都是一個表達式,例如一個方法調用或類似 x < y 的二進制運算。

表達式樹是Lambda表達式的一種高效的記憶體中資料表現形式,并且使得表達式的結構變得透明和明顯。

C# Lambda表達式樹要點:

                1. Lambda表達式的參數類型可以忽略,因為可以根據使用的上下文進行推斷。

                2. Lambda表達式的主體(body)可以是表達式,也可以是語句塊。

                3. Lambda表達式傳入的實參将參與類型推斷,以及方法重載辨析。

                4. Lambda表達式和表達式體可以被轉換為表達式樹。

                5. 表達式樹允許lambda表達式能夠代表資料結構替代表示為執行代碼。

Expression<Func<int, int>> expression = x => x + 5;
           Console.WriteLine(expression.Parameters[0]);
           Console.WriteLine(expression.Body);
           //執行Expression表達式
           Func<int, int> fx = expression.Compile();
           Console.WriteLine(fx(5));
           

3,Linq

LINQ 提供一種跨各種資料源和資料格式使用資料的一緻模型,所有 LINQ 查詢操作都由以下三個不同的操作組成: 擷取資料源。建立查詢。執行查詢。
public static void Run()
        {
            //用 Linq執行簡單的數組查詢
            int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
 
            //延遲執行
            //var numberQuery = from num in numbers
            //                  where (num % 2) == 0
            //                  select num;
 
            //強制立即執行
            List<int> numberQuery = (from num in numbers
                                     where (num % 2) == 0
                                     select num).ToList();
            //或者
            var numberArray = (from num in numbers
                               where (num % 2) == 0
                               select num).ToArray();
 
            //查詢變量本身隻是存儲查詢指令。實際的查詢執行會延遲到在 foreach 語句中循環通路查詢變量時發生。此概念稱為“延遲執行”
            foreach (var item in numberQuery)
            {
                Console.WriteLine(item);
            }
        }
           
Linq To List 集合查詢
//本篇介紹Linq對集合的各種查詢
      public static void Run()
      {
          List<Customers> customerlist = new List<Customers>();
          customerlist.Add(new Customers() { id = 1, Name = "Jack", Custom = "Mis" });
          customerlist.Add(new Customers() { id = 2, Name = "Lus", Custom = "Google" });
          customerlist.Add(new Customers() { id = 3, Name = "Qiao", Custom = "Baidu" });
          customerlist.Add(new Customers() { id = 4, Name = "Qiao", Custom = "Apple" });
          customerlist.Add(new Customers() { id = 5, Name = "Adb", Custom = "Adobe" });
 
          //簡單的查詢
          var customerQuery = from query in customerlist
                              select query;
 
          //帶where篩選
          var customerWhereQuery = from query in customerlist
                                   where query.id == 1 && query.Name == "Lus"
                                   select query;
 
          //排序Ordering
          var customerOrderingQuery = from query in customerlist
                                      where query.Name == "Lus"
                                      orderby query.id ascending
                                      select query;
 
          //分組Group by
          var customerGroupbyQuery = from query in customerlist
                                     group query by query.Name;
          //可以使用into進一步查詢
          var customerGroupbyIntoQuery = from query in customerlist
                                         group query by query.Name into queryGroup
                                         where queryGroup.Key == "Qiao"
                                         select queryGroup;
          //聯接查詢 join 子句始終針對對象集合而非直接針對資料庫表運作。
          List<Customers> customerJoinlist = new List<Customers>();
          customerJoinlist.Add(new Customers() { id = 1, Name = "Jack", Custom = "Mis" });
          customerJoinlist.Add(new Customers() { id = 2, Name = "Lus", Custom = "Google" });
          customerJoinlist.Add(new Customers() { id = 3, Name = "Qiao", Custom = "Baidu" });
          var customerJoinQuery = from query1 in customerlist
                                  join query2 in customerJoinlist
                                  on query1.id equals query2.id
                                  select new { CustomerName = query1.Name, CustomerName2 = query2.Name };
 
          //資料源的類型參數始終為查詢中的範圍變量的類型。
          //比如List<Customers> 類型為Customers 在循環疊代的時候類型必須可以隐式轉換為Customer 有一種情況是
          //這種情況下Customers類型轉換為了String ..在select query.Name已經将查詢目标類型定位了String類型
          var customerTypeQuery = from query in customerlist
                                  where query.Name == "Lus"
                                  select query.Name;
 
          //結合Lamdba對List集合篩選(s => s.Name == "Qiao")
          List<Customers> listString = customerlist.Where(s => s.Name == "Qiao").ToList();
 
 
      }
  }
 
  public class Customers
  {
      public int id { get; set; }
 
      public string Name { get; set; }
 
      public string Custom { get; set; }
  }
           

Linq To SQL

首先連接配接NORTHWRN資料庫 為了做列子簡單的把Customers表拖放到dbml檔案.也就是LinqToSQL類

public static void Run()
      {
          DataClasses1DataContext dataContext = new DataClasses1DataContext();
 
          //對Customers資料源執行簡單查詢
          var custQuery = from custom in dataContext.Customers
                          where custom.City == "Seattle"
                          select custom;
          //添加實體
          Customers customers = new Customers()
          {
              ContactName = "AdventureWorks Cafe",
              Address = "Google",
              CustomerID = "ADVAS"
          };
          dataContext.Customers.InsertOnSubmit(customers);
 
          //更新實體
          var updateCustomer = (from c in dataContext.Customers
                                where c.CustomerID == "ADVAS"
                                select c).First();
          updateCustomer.ContactName = "New Name";
          //送出更改
          dataContext.SubmitChanges();
 
          //删除實體
          List<Customers> deleteCustomer = (from c in dataContext.Customers
                               where c.id >= 1000
                               select c).ToList();
          //批量删除
          dataContext.Customers.DeleteAllOnSubmit(deleteCustomer);
      }

           

4,Dynamic

     Visual C# 2010 引入了一個新類型 dynamic。 該類型是一種靜态類型,但類型為 dynamic 的對象會跳過靜态類型檢查。 大多數情況下,該對象就像具有類型 object 一樣。 在編譯時,将假定類型化為 dynamic 的元素支援任何操作。 是以,您不必考慮對象是從 COM API、從動态語言(例如 IronPython)、從 HTML 文檔對象模型 (DOM)、從反射還是從程式中的其他位置擷取自己的值。但是,如果代碼無效,則在運作時會捕獲到錯誤。  

    在通過 dynamic 類型實作的操作中,該類型的作用是繞過編譯時類型檢查, 改為在運作時解析這些操作。該類型簡化了對 COM API(例如 Office Automation API)、例動态 API(如 IronPython 庫)和 HTML 文檔對象模型 (DOM) 的通路。

    在大多數情況下, dynamic 類型與 object 類型的行為是一樣的。 但是,不會用編譯器對包含 dynamic 類型表達式的操作進行解析或類型檢查。 編譯器将有關該操作資訊打包在一起,并且該資訊以後用于計算運作時操作。在此過程中,類型 dynamic 的變量會編譯到類型 object 的變量中。 是以,類型 dynamic 隻在編譯時存在,在運作時則不存在。

public class DynamicExample
    {
        public static void Run()
        {
            dynamic dyn = "j";
            object obj = 1;
            dynamic dyng = GetDyn("哈哈");
 
            //運作時檢查
            Console.WriteLine((dyn + 3).GetType());
            //編譯報錯
            //Console.WriteLine(obj + 3);
            Console.WriteLine(dyng + " " + dyng.GetType());
        }
 
        public static dynamic GetDyn(object obj) 
        {
            return obj;
        }
    }

           

繼續閱讀