zoukankan      html  css  js  c++  java
  • 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));
    }
    }
    }
  • 相关阅读:
    linux基础
    1-1python自动化测试环境搭建及开发工具安装
    Linux常用命令
    049.NET5_中间件
    045.NET5_基本鉴权授权
    044.NET5_基于Session_Cookies认证
    042-043.NET5_ResultFilter以及双语言应用
    041.NET5_ExceptionFilter
    040.NET5_ExceptionFilter
    039.NET5_自定义Filter匿名
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1745325.html
Copyright © 2011-2022 走看看