有意思的lambda表达式

2008年05月25日 | 218 次浏览 | 学习  

有这么一种场景,有一个Category的实体类对应着一个名为Category的数据库表。Category类中有Name和Path属性,在新建或更新Category对象时要保证这两个属性在数据库中的值唯一。当然你可以在数据库中的Name和Path字段都建一个唯一索引,那如果不采用这种做法应该怎么做呢?最简单的方法就是写两个名为CheckNameValid和CheckPathValid的函数。很明显这种做法不易于维护,比如说当Category类增加其他需要保证唯一的属性或者属性名字需要改变的时候。我的写法如下:

  1. /// <summary>
  2. /// 检查数据库字段中的值是否唯一
  3. /// </summary>
  4. /// <param name="t">Cateroy的集合</param>
  5. /// <param name="func">表达式</param>
  6. /// <param name="isNew">是否是新建Category</param>
  7. /// <returns></returns>
  8. protected bool CheckValid(
  9.                 IEnumerable<Category> t,
  10.                 Func<Category, Boolean> func,
  11.                 bool isNew)
  12. {
  13.     Category c = t.SingleOrDefault(func);
  14.     if (isNew)
  15.         return c == null;
  16.     else
  17.         return c == null || (c != null && c.ID == Convert.ToInt32(ID.Text));
  18. }
  19.  
  20. //调用方法一
  21. protected Func<Category, Boolean> func = null;
  22. protected void Page_Load(object sender, EventArgs e)
  23. {
  24.     func = selectCategory;
  25. }
  26. protected bool selectCategory(Category c)
  27. {
  28.     return c.Name == this.Name.Text;
  29. }
  30. CheckValid(kr.Categories, selectCategory, true);
  31. //调用方法二
  32. CheckValid(kr.Categories, delegate(Category c){ 
  33.         return c.Name == Name.Text;
  34.     }
  35.     , true);
  36. CheckValid(kr.Categories, delegate(Category c){ 
  37.         return c.Path == Path.Text;
  38.     }
  39.     , false);
  40. //调用方法三
  41. CheckValid(kr.Categories, c => c.Name == Name.Text, true);
  42. CheckValid(kr.Categories, c => c.Path == Path.Text, false);

三种调用方法,当然是使用了lambda表达式的方法三最简洁明了。还可以扩展一下,可以把它写成某个Utility类泛型静态方法,专门检查实体类在数据库字段中的值是否唯一,这时Convert.ToInt32(ID.Text)就要抽出来做成一个参数,这里不就写了。

另外在瘦子师兄的点拨下,发现C# 3.0里面有个类似Javascript中prototype的概念,称为扩展方法(Extension Methods),在System.Linq中运用了大量的扩展方法(例如前面例子中的SingleOrDefault)。扩展方法貌似没prototype灵活,比较的例子如下:

  1. public static class Program 
  2. {
  3.     public static void Main(string [] args)
  4.     {
  5.         string s = "Hello World";
  6.         s.Print();
  7.         s.ToString();
  8.         Console.WriteLine(s.ToString());
  9.         Console.Read();
  10.     }
  11. }
  12. public static class Tools
  13. {
  14.     public static void Print(this string s)
  15.     {
  16.         Console.WriteLine(s.ToUpper());
  17.     }
  18.     public static void ToString(this string s)
  19.     {
  20.         Console.WriteLine(s.ToUpper());
  21.     }
  22. }
  1. function A(){this.name = "AA";}
  2. A.prototype = {
  3.     show:function(){ alert(this.name);}
  4. }
  5. var a1 = new A();
  6. a1.show();
  7. //直接覆写A的prototype中的show
  8. A.prototype.show = function(){ alert("modified:"+this.name);}
  9. var a2 = new A();
  10. a2.name = "a2";
  11. a2.show();

对于一个你不能修改源代码的类,可以通过这种方式为它添加方法。但这个只是编译期的(s.Print()翻译成tools.Print(s)),也就是说编译之后是不能通过反射来取得它的,它并不是要扩展类(例子中的String类)中的真正方法,而是某个静态类(例子中的Tools)的静态方法。
具体介绍参见这篇文章Deep Dive on Extension Methods

评论

Comment RSS TrackBack URI

相关推荐:

发表评论

更多文章

最受欢迎

评论最多