转载地址:http://www.cnblogs.com/ldp615/archive/2011/08/01/distinct-entension.html

刚看了篇文章 《Linq的Distinct太不给力了》,文中给出了一个解决办法,略显复杂。

试想如果能写成下面的样子,是不是更简单优雅:

1
2
var p1 = products.Distinct(p => p.ID);
var p2 = products.Distinct(p => p.Name);

使用一个简单的 lambda 作为参数,也符合 Linq 一贯的风格。

可通过扩展方法实现:

Distinct 扩展方法

首先,创建一个通用比较的类,实现 IEqualityComparer<T> 接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Linq;public class CommonEqualityComparer<T, V> : IEqualityComparer<T>
{private Func<T, V> keySelector;public CommonEqualityComparer(Func<T, V> keySelector){this.keySelector = keySelector;}public bool Equals(T x, T y){return EqualityComparer<V>.Default.Equals(keySelector(x), keySelector(y));}public int GetHashCode(T obj){return EqualityComparer<V>.Default.GetHashCode(keySelector(obj));}
}

第 17 行,用到了 EqualityComparer<T> 类,本文最后有简要说明。

借助上面这个类,Distinct 扩展方法就很好写了:

1
2
3
4
5
6
7
public static class DistinctExtensions
{public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector){return source.Distinct(new CommonEqualityComparer<T, V>(keySelector));}
}

呵呵,简单吧!

Distinct 使用示例

根据 ID :

1
2
3
4
5
6
7
var data1 = new Person[] {new Person{ ID = 1, Name = "鹤冲天"},new Person{ ID = 1, Name = "ldp"}
};
var ps1 = data1.Distinct(p => p.ID).ToArray();

根据 Name:

1
2
3
4
5
7
var data2 = new Person[] {new Person{ ID = 1, Name = "鹤冲天"},new Person{ ID = 2, Name = "鹤冲天"}
};
var ps2 = data2.Distinct(p => p.Name).ToArray();

看了回复后,我做了些改进,推荐使用下面的方式

改进

回复中有朋友提到“不区分大小写地排除重复的字符串”,也不难实现,只需要把上面的代码改进下就 OK:

CommonEqualityComparer<T, V> 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Linq;public class CommonEqualityComparer<T, V> : IEqualityComparer<T>
{private Func<T, V> keySelector;private IEqualityComparer<V> comparer;public CommonEqualityComparer(Func<T, V> keySelector, IEqualityComparer<V> comparer){this.keySelector = keySelector;this.comparer = comparer;}public CommonEqualityComparer(Func<T, V> keySelector): this(keySelector, EqualityComparer<V>.Default){  }public bool Equals(T x, T y){return comparer.Equals(keySelector(x), keySelector(y));}public int GetHashCode(T obj){return comparer.GetHashCode(keySelector(obj));}
}

Distinct 扩展方法:

1
2
3
4
5
6
7
8
9
10
11
12
public static class DistinctExtensions
{public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector){return source.Distinct(new CommonEqualityComparer<T, V>(keySelector));}public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector, IEqualityComparer<V> comparer){return source.Distinct(new CommonEqualityComparer<T, V>(keySelector, comparer));}
}

借助可选参数,这两个扩展方法也可以合成一个:

1
2
3
4
5
public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector,
    IEqualityComparer<V> comparer = EqualityComparer<V>.Default)
{return source.Distinct(new CommonEqualityComparer<T, V>(keySelector, comparer));
}

(同样,CommonEqualityComparer<T, V>类的两个构造函数也可以合二为一)

使用示例:

1
2
3
4
5
6
7
var data3 = new Person[] {new Person{ ID = 1, Name = "LDP"},new Person{ ID = 2, Name = "ldp"}
};
var ps3 = data3.Distinct(p => p.Name, StringComparer.CurrentCultureIgnoreCase).ToArray();

EqualityComparer<T> 类 简要说明

EqualityComparer<T>为 IEqualityComparer<T> 泛型接口的实现提供基类,它在 .net 4 中有五个重要的子类,见下图:

这五个子类分别用不同类型数据的相等性比较,从类名我们可以略知一二。

这五个子类都是内部类(internal),不能直接访问,EqualityComparer<T> 类提供一个简单的属性 Default。EqualityComparer<T> 会根据传入的 T 的类型,加载不同的子类,并会予以缓存提高性能。

c#扩展方法奇思妙用》系统文章从 2009 年 08 月开始写起,到现在一共有了 22 篇,欢迎阅读:

基础篇: 中文处理、string 常用扩展、byte 常用扩展、Random 扩展、Dictionary<TKey, TValue> 扩展、WhereIf 扩展、IsBetween 通用扩展、WhereIf 扩展、Distinct 扩展
高级篇: 改进 Scottgu 的 "In" 扩展、Aggregate扩展其改进、Enumerable.Cast<T>应用、对扩展进行分组管理、ToString(string format) 扩展、WinForm 控件选择器、树”通用遍历器、Type类扩展
变态篇: 由Fibonacci数列引出“委托扩展”及“递推递归委托”、封装 if/else、swith/case及while、switch/case 组扩展、string 的翻身革命
性能篇 扩展方法性能初测
MVC篇: 巧用扩展方法优先级,美化所有页面TextBoxFor文本框

-------------------

转载于:https://www.cnblogs.com/yxlblogs/p/3737164.html

c# 扩展方法奇思妙用基础篇八:Distinct 扩展(转载)相关推荐

  1. c#扩展方法奇思妙用性能篇一:扩展方法性能初测

    最近写了几篇<c#扩展方法奇思妙用>的文章,一直只是讨论如何扩展.如何使用的问题,几乎没有涉及效率方面. 而大家的回复好多都在问效率如何.性能怎样,也引起了我对效率的关注,今天将初步测试的 ...

  2. c#扩展方法奇思妙用高级篇八:Type类扩展

    Type 类提供了大量的属性和方法,但在一些基础性开发工作中,Type类功能还有些欠缺,尤其上在处理泛型类型时,如可空类型和泛型集合类型.下面的类就针对这些地方进行扩展.  1     public  ...

  3. c#扩展方法奇思妙用高级篇七:“树”通用遍历器

    我的上一篇随笔<c#扩展方法奇思妙用高级篇六:WinForm 控件选择器>中给出了一个WinForm的选择器,其实质就是一个"树"的遍历器,但这个遍历局限于WinFor ...

  4. c#扩展方法奇思妙用高级篇四:对扩展进行分组管理

    从系列文章开篇到现在,已经实现的很多扩展了,但过多的扩展会给我们带来很多麻烦,试看下图: 面对这么多"泛滥"的扩展,很多人都会感到很别扭,的确有种"喧宾夺主"的 ...

  5. c# 扩展方法奇思妙用变态篇四:string 的翻身革命

    string是各种编程语言中最基础的数据类型,长期以来受尽其它类的压迫,经常被肢解(Substring.Split).蹂躏(Join)... 而现在string要"翻身闹革命"了, ...

  6. c#扩展方法奇思妙用变态篇四:string 的翻身革命

    string是各种编程语言中最基础的数据类型,长期以来受尽其它类的压迫,经常被肢解(Substring.Split).蹂躏(Join)... 而现在string要"翻身闹革命"了, ...

  7. c# 扩展方法奇思妙用高级篇一:改进 Scottgu 的 In 扩展

    先看下ScottGu对In的扩展: 调用示例1: 调用示例2: 原文地址:New "Orcas" Language Feature: Extension Methods 很多介绍扩 ...

  8. c# 扩展方法奇思妙用变态篇一:由 Fibonacci 数列引出 “委托扩展” 及 “递推递归委托”...

    先回顾一个数列的概念:按一定次序排列的一列 数 称为数列...(请参见百度百科:数列) 几个简单的数列:       1, 1, 1, 1, 1, 1, 1...                //数 ...

  9. C#扩展方法奇思妙用高级篇一:改进 Scottgu 的 In 扩展

    先看下ScottGu对In的扩展: 调用示例1: 调用示例2: 原文地址:New "Orcas" Language Feature: Extension Methods 很多介绍扩 ...

最新文章

  1. 1行Python代码制作动态二维码
  2. python使用fpdf生成数据报告pdf文件
  3. 物联网白皮书【2018】重磅发布|今年的物联网产业交出了一张怎样的答卷
  4. 将现有Git存储库推送到SVN
  5. 在Nature都点赞的大会上,马斯克被「脑机接口之父」炮轰了:他说的话,我一个字都不认同...
  6. 解决Windows环境下Git Bash 不能输入中文的问题
  7. 卸载VS2005不完全出现的安装问题
  8. Java中static的用法,初始化块
  9. 如何使用bat批处理命令打开WSL
  10. 苹果开发者中心如何上传构建版本
  11. postgreSQL 获取当前连接的IP
  12. Linux 修改hosts文件
  13. raid5硬盘插到计算机读取,【哭着写下这篇文章】win2008软raid5变成2个磁盘组的数据恢复...
  14. Fabric学习笔记(六) - chaincode开发模式
  15. python opencv 入门 绘图函数 (3)
  16. Unity开发3 坐标系及工具、快捷键操作
  17. 恭喜!第十届“吴文俊人工智能科学技术奖”揭晓!华章多位作译者获奖
  18. 路由器端口转发数量限制_路由器可以同时处理的设备数量是否有限制?
  19. 软件快捷方式测试用例,用TestDirector生成的测试用例
  20. 码讯化工人员定位系统/支持无线WiFi|UWB定位

热门文章

  1. Lua源码分析 - 基础篇 - Lua源码的结构和架构图(01)
  2. 非常值得一看—九种滤波算法C语言实现
  3. java 远程shell脚本_java通过ssh连接服务器执行shell命令详解及实例
  4. mysql的内连接查询
  5. c++ primer 5th p289页练习题自己的解答程序
  6. 让C++对象只能分配到堆/栈和静态区上并判断分配位置
  7. 概率论-4.2中心极限定理(待补充)
  8. 对于原生代码使用Java线程的优缺点
  9. 华为手机如何升级鸿蒙系统_华为官方正式公告!鸿蒙手机系统下周发布:普通花粉何时能升级?...
  10. Apache Hadoop 简单配置及实践