程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> C#教程:使用lambda表達式記錄事件日志

C#教程:使用lambda表達式記錄事件日志

編輯:關於.NET

使用List<T>和事件的簡單例子

如果你記得List<T>當中的FindAll()方法, 其要求一個Predicate<T>參數並且返回一個新的列表, 該列表包含的所有元素都滿足輸入斷言(predicate). Sort方法要求一個Comparison<T>參數然後按序排列整個列表. 以下的例子使用了lambda表達式提供了委托實例給每一個方法. 示例數據是不同電影的名稱和發行年限. 我們將打印出原始的列表, 然後創建並打印出一個過濾的只包含老電影的列表, 並按名稱排序打印出原始列表.

   1: class Film
   2: {
   3: public string Name { get; set; }
   4: public int Year { get; set; }
   5: public override string ToString()
   6: {
   7: return string.Format("Name={0}, Year={1}", Name, Year);
   8: }
   9: }
  10: ...
  11: var films = new List<Film>
  12: {
  13: new Film {Name="Jaws", Year=1975},
  14: new Film {Name="Singing in the Rain", Year=1952},
  15: new Film {Name="Some Like It Hot", Year=1959},
  16: new Film {Name="The Wizard of Oz", Year=1939},
  17: new Film {Name="It's a Wonderful Life", Year=1946},
  18: new Film {Name="American Beauty", Year=1999},
  19: new Film {Name="High Fidelity", Year=2000},
  20: new Film {Name="The Usual Suspects", Year=1995}
  21: };
  22: Action<Film> print = film => { Console.WriteLine(film); };
  23: films.ForEach(print);
  24: films.FindAll(film => film.Year < 1960)
  25: .ForEach(print);
  26: films.Sort((f1, f2) => f1.Name.CompareTo(f2.Name));
  27: films.ForEach(print);

代碼的前半部分主要是數據的准備, 我們使用了匿名類, 其是一個泛型列表實例. 在開始使用這個列表之前, 我們創建了一個委托實例, 我們將會使用這個實例來打印列表.這就是為什麼我使用了一個變量來保存該實例, 而不是每次都使用一個單獨的lambda表達式. 它僅僅打印了一個元素, 但是將它傳遞給List<T>.ForEach方法我們可以整個列表元素都輸出到控制台.

我們打印的第一個列表是沒有任何編輯的原始列表, 接下來我們查找並打印出了所有發行年限在1960年之前的電影. 我們使用了另外一個lambda表達式來完成這項工作, 列表中的每一個項都會執行該表達式——它用於決定該元素是否應該出現在新的過濾列表當中. 源代碼當中使用了lambda表達式作為方法參數, 然而編譯器實際上是類似下面代碼一樣創建了一個方法:

   1: private static bool SomeAutoGeneratedName(Film film)
   2: {
   3: return film.Year < 1960;
   4: }

FindAll方法調用將會類似下面這樣:

   1: films.FindAll(new Predicate<Film>(SomeAutoGeneratedName))

這裡對於lambda表達式的支持與C# 2中的匿名方法一致, 這就是編譯器的聰明之處. (實際上, 微軟的編譯器在這個例子中甚至還更加聰明——它甚至能夠意識到如果代碼再次被調用, 委托類型可能會再次被使用, 因此會將它緩存.)

排序部分同樣也是使用了一個lambda表達式, 其通過名字進行了比較. 我不得不承認顯式調用CompareTo有點丑陋, 在下面一節當中我們將看到如何使用OrderBy擴展方法來更簡潔的排序.

使用lambda表達式記錄事件日志

   1: static void Log(string title, object sender, EventArgs e)
   2: {
   3:     Console.WriteLine("Event: {0}", title);
   4:     Console.WriteLine(" Sender: {0}", sender);
   5:     Console.WriteLine(" Arguments: {0}", e.GetType());
   6:     foreach (PropertyDescriptor prop in
   7:     TypeDescriptor.GetPropertIEs(e)){
   8:     string name = prop.DisplayName;
   9:     object value = prop.GetValue(e);
  10:     Console.WriteLine(" {0}={1}", name, value);
  11: }
  12:  
  13: ...
  14: Button button = new Button();
  15: button.Text = "Click me";
  16: button.Click += (src, e) => { Log("Click", src, e); };
  17: button.KeyPress += (src, e) => { Log("KeyPress", src, e); };
  18: button.MouseClick += (src, e) => { Log("MouseClick", src, e); };
  19: Form form = new Form();
  20: form.AutoSize=true;
  21: form.Controls.Add(button);
  22: Application.Run(form);

上述的代碼使用了lambda表達式來傳遞事件名和參數到Log方法, 該方法記錄了事件的一些詳細信息. 我們並沒有記錄源事件的所有信息, 而僅僅是調用了ToString()重載方法, 因為控件本身承載了大量的信息. 實際上, 我們使用了反射來遍歷了屬性的descriptor信息, 這裡是一個可能的輸出結果:

   1: Event: Click
   2: Sender: System.Windows.Forms.Button, Text: Click me
   3: Arguments: System.Windows.Forms.MouseEventArgs
   4: Button=Left
   5: Clicks=1
   6: X=53
   7: Y=17
   8: Delta=0
   9: Location={X=53,Y=17}
  10: Event: MouseClick
  11: Sender: System.Windows.Forms.Button, Text: Click me
  12: Arguments: System.Windows.Forms.MouseEventArgs
  13: Button=Left
  14: Clicks=1
  15: X=53
  16: Y=17
  17: Delta=0
  18: Location={X=53,Y=17}

所有的這些不通過lambda表達式當然也可以做到, 不過使用lambda表達式相比其他的做法更加簡潔.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved