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

时间:2023-03-10 07:11:37
Lambda表达式, 可以让我们的代码更优雅.

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

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

下面两个语句是等价的

 Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/-->//using delegate syntax
Func<int, int> f = delegate(int i) { return ++i; }; //using lambda syntax
Func<int, int> f = i => ++i;

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

 Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/-->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=,
Title="Design Patterns",
Authors= new List<string>{"Erich Gamma", "Richard Helm", "Ralph Johnson", "John Vlissides"}
}, new Book
{
Id=,
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>应该提供了这样的方法:

 Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/-->1 //判断是否存在Id==1的书
bool has_book_with_id_equals_one = books.Contains(new Book { Id = }, (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>没有这样的方法。

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

 Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/--> 1 //新增一个实现了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 = }, new BookComparer());

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

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

 Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/--> 1 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

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

 Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/-->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=,
Title="Design Patterns",
Authors= new List<string>{"Erich Gamma", "Richard Helm", "Ralph Johnson", "John Vlissides"}
}, new Book
{
Id=,
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 = }, (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));
}
}
}

相关文章