您的位置:首页 > 编程语言

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

2010-05-27 13:50 856 查看
在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>应该提供了这样的方法:

//判断是否存在Id==1的书
bool has_book_with_id_equals_one = books.Contains(new Book { Id = 1 }, (x, y) => x.Id == y.Id);

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


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

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

//新增一个实现了IEqualityComparer<Book>接口的类
public class BookComparer : IEqualityComparer<Book>
{
public bool Equals(Book x, Book y)
{
return x.Id == y.Id;
}
public int GetHashCode(Book obj)
{
return obj.Id.GetHashCode();
}
}
//然后再干我们的活
bool has_book_with_id_equals_one = books.Contains(new Book { Id = 1 }, new BookComparer());


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

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

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();
}
}
}

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));
}
}


注意到上面的代码不仅仅针对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));
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐