Lambda表达式, 可以让我们的代码更优雅.


在C#中, 适当地使用Lambda表达式, 可以让我们的代码更优雅.

通过lambda表达式, 我们可以很方便地创建一个delegate:

下面两个语句是等价的

//using delegate syntax
Func<int, int> f = delegate(int i) { return ++i; };

//using lambda syntax
Func<int, int> f = i => ++i;

但我更喜欢后者!

假如我要对一个列表进行排序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List
<Book> books = new List<Book>
{
new Book
{
Id
=1,
Title
="Design Patterns",
Authors
= new List<string>{"Erich Gamma", "Richard Helm", "Ralph Johnson", "John Vlissides"}
},

new Book
{
Id
=2,
Title
="Refactoring",
Authors
= new List<string>{"Martin Fowler"}
}
};

books.Sort((x, y)
=> x.Authors.Count - y.Authors.Count); //以作者个数进行排序
}
}

public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public List<string> Authors { get; set; }
}
}

的确很方便吧!

我猜想List<T>应该提供了这样的方法:

1 //判断是否存在Id==1的书
2 bool has_book_with_id_equals_one = books.Contains(new Book { Id = 1 }, (x, y) => x.Id == y.Id);
3
4 //判断是否存在Title=="REFACTORING"(不区分大小写)的书
5 bool has_book_with_title_equals_refactoring_ignorecase = books.Contains(new Book { Title = "REFACTORING" }, x => x.Title.ToUpper());

不幸的是, List<T>没有这样的方法。

按照传统的方法, 你可能会这样写:

 1     //新增一个实现了IEqualityComparer<Book>接口的类
2 public class BookComparer : IEqualityComparer<Book>
3 {
4 public bool Equals(Book x, Book y)
5 {
6 return x.Id == y.Id;
7 }
8 public int GetHashCode(Book obj)
9 {
10 return obj.Id.GetHashCode();
11 }
12 }
13 //然后再干我们的活
14 bool has_book_with_id_equals_one = books.Contains(new Book { Id = 1 }, new BookComparer());

很无奈的选择, 但是没办法!

幸运的是,我们可以自己动手扩展List<T>接口:

 1     public class KeyEqualityComparer<T> : IEqualityComparer<T>
2 {
3 private readonly Func<T, T, bool> comparer;
4 private readonly Func<T, object> keyExtractor;
5
6 // Allows us to simply specify the key to compare with: y => y.ID
7 public KeyEqualityComparer(Func<T, object> keyExtractor) : this(keyExtractor, null) { }
8
9 // Allows us to tell if two objects are equal: (x, y) => y.Id == x.Id
10 public KeyEqualityComparer(Func<T, T, bool> comparer) : this(null, comparer) { }
11
12 public KeyEqualityComparer(Func<T, object> keyExtractor, Func<T, T, bool> comparer)
13 {
14 this.keyExtractor = keyExtractor;
15 this.comparer = comparer;
16 }
17
18 public bool Equals(T x, T y)
19 {
20 if (comparer != null)
21 return comparer(x, y);
22 else
23 {
24 var valX = keyExtractor(x);
25 if (valX is IEnumerable<object>) // The special case where we pass a list of keys
26 return ((IEnumerable<object>)valX).SequenceEqual((IEnumerable<object>)keyExtractor(y));
27 return valX.Equals(keyExtractor(y));
28 }
29 }
30
31 public int GetHashCode(T obj)
32 {
33 if (keyExtractor == null)
34 return obj.ToString().ToLower().GetHashCode();
35 else
36 {
37 var val = keyExtractor(obj);
38 if (val is IEnumerable<object>) // The special case where we pass a list of keys
39 return (int)((IEnumerable<object>)val).Aggregate((x, y) => x.GetHashCode() ^ y.GetHashCode());
40 return val.GetHashCode();
41 }
42 }
43 }
44
45 public static class MyExtMethod
46 {
47 public static bool Contains<T>(this IEnumerable<T> list, T item, Func<T, object> keyExtractor)
48 {
49 return list.Contains(item, new KeyEqualityComparer<T>(keyExtractor));
50 }
51
52 public static bool Contains<T>(this IEnumerable<T> list, T item, Func<T, T, bool> comparer)
53 {
54 return list.Contains(item, new KeyEqualityComparer<T>(comparer));
55 }
56 }

注意到上面的代码不仅仅针对Book,而是任意类型T

现在,我们就可以无拘无束地用我们的自己的扩展方法了(完整代码):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List
<Book> books = new List<Book>
{
new Book
{
Id
=1,
Title
="Design Patterns",
Authors
= new List<string>{"Erich Gamma", "Richard Helm", "Ralph Johnson", "John Vlissides"}
},

new Book
{
Id
=2,
Title
="Refactoring",
Authors
= new List<string>{"Martin Fowler"}
}
};

books.Sort((x, y)
=> x.Authors.Count - y.Authors.Count);

bool has_book_with_id_equals_one = books.Contains(new Book { Id = 1 }, (x, y) => x.Id == y.Id);

bool has_book_with_title_equals_refactoring_ignorecase = books.Contains(new Book { Title = "REFACTORING" }, x => x.Title.ToUpper());

}
}

public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public List<string> Authors { get; set; }
}


public class KeyEqualityComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> comparer;
private readonly Func<T, object> keyExtractor;

// Allows us to simply specify the key to compare with: y => y.Id
public KeyEqualityComparer(Func<T, object> keyExtractor) : this(keyExtractor, null) { }

// Allows us to tell if two objects are equal: (x, y) => y.Id == x.Id
public KeyEqualityComparer(Func<T, T, bool> comparer) : this(null, comparer) { }

public KeyEqualityComparer(Func<T, object> keyExtractor, Func<T, T, bool> comparer)
{
this.keyExtractor = keyExtractor;
this.comparer = comparer;
}

public bool Equals(T x, T y)
{
if (comparer != null)
return comparer(x, y);
else
{
var valX
= keyExtractor(x);
if (valX is IEnumerable<object>) // The special case where we pass a list of keys
return ((IEnumerable<object>)valX).SequenceEqual((IEnumerable<object>)keyExtractor(y));
return valX.Equals(keyExtractor(y));
}
}

public int GetHashCode(T obj)
{
if (keyExtractor == null)
return obj.ToString().ToLower().GetHashCode();
else
{
var val
= keyExtractor(obj);
if (val is IEnumerable<object>) // The special case where we pass a list of keys
return (int)((IEnumerable<object>)val).Aggregate((x, y) => x.GetHashCode() ^ y.GetHashCode());
return val.GetHashCode();
}
}
}

/// <summary>
/// 扩展方法
/// </summary>
public static class MyExtMethod
{
public static bool Contains<T>(this IEnumerable<T> list, T item, Func<T, object> keyExtractor)
{
return list.Contains(item, new KeyEqualityComparer<T>(keyExtractor));
}

public static bool Contains<T>(this IEnumerable<T> list, T item, Func<T, T, bool> comparer)
{
return list.Contains(item, new KeyEqualityComparer<T>(comparer));
}
}
}

优质内容筛选与推荐>>
1、Windows 下使用 MinGW 和 CMake 进行开发
2、c#中 线程访问控件的解决方法 可直接调用此方法
3、JSP 动作元素
4、python 判断质数还是合数
5、Probabilistic Graphical Models 10-708, Spring 2017


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn