• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C#教程 > 为何Linq的Distinct实在是不给力

为何Linq的Distinct实在是不给力

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了linq distinct,linq distinct用法,c linq distinct,linq to sql distinct,linq distinctby等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com
假设我们有一个类:Product

public class Product
{
    public string Id { get; set; }
    public string Name { get; set; }
}
Main函数如下:
static void Main()
{
    List<Product> products = new List<Product>()
    {
        new Product(){ Id="1", Name="n1"},
        new Product(){ Id="1", Name="n2"},
        new Product(){ Id="2", Name="n1"},
        new Product(){ Id="2", Name="n2"},
    };
    var distinctProduct = products.Distinct();
    Console.ReadLine();
}
可以看到distinctProduct 的结果是:

image

因为Distinct 默认比较的是Product对象的引用,所以返回4条数据。
那么如果我们希望返回Id唯一的product,那么该如何做呢?
 
Distinct方法还有另一个重载:
//通过使用指定的 System.Collections.Generic.IEqualityComparer<T> 对值进行比较
//返回序列中的非重复元素。
 public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source,
IEqualityComparer<TSource> comparer);
该重载接收一个IEqualityComparer的参数。
假设要按Id来筛选,那么应该新建类ProductIdComparer 内容如下:
public class ProductIdComparer : IEqualityComparer<Product>
{
    public bool Equals(Product x, Product y)
    {
        if (x == null)
            return y == null;
        return x.Id == y.Id;
    }
    public int GetHashCode(Product obj)
    {
        if (obj == null)
            return 0;
        return obj.Id.GetHashCode();
    }
}
使用的时候,只需要
var distinctProduct = products.Distinct(new ProductIdComparer());
结果如下:

image

现在假设我们要 按照 Name来筛选重复呢?
很明显,需要再添加一个类ProductNameComparer.
那能不能使用泛型类呢??
新建类PropertyComparer<T> 继承IEqualityComparer<T> 内容如下:
public class PropertyComparer<T> : IEqualityComparer<T>
{
    private PropertyInfo _PropertyInfo;
    /// <summary>
    /// 通过propertyName 获取PropertyInfo对象   
    /// </summary>
    /// <param name="propertyName"></param>
    public PropertyComparer(string propertyName)
    {
        _PropertyInfo = typeof(T).GetProperty(propertyName,
        BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public);
        if (_PropertyInfo == null)
        {
            throw new ArgumentException(string.Format("{0} is not a property of type {1}.",
                propertyName, typeof(T)));
        }
    }
    #region IEqualityComparer<T> Members
    public bool Equals(T x, T y)
    {
        object xValue = _PropertyInfo.GetValue(x, null);
        object yValue = _PropertyInfo.GetValue(y, null);
        if (xValue == null)
            return yValue == null;
        return xValue.Equals(yValue);
    }
    public int GetHashCode(T obj)
    {
        object propertyValue = _PropertyInfo.GetValue(obj, null);
        if (propertyValue == null)
            return 0;
        else
            return propertyValue.GetHashCode();
    }
    #endregion
}

主要是重写的Equals 和GetHashCode 使用了属性的值比较。
使用的时候,只需要:
//var distinctProduct = products.Distinct(new PropertyComparer<Product>("Id"));
var distinctProduct = products.Distinct(new PropertyComparer<Product>("Name"));

结果如下:

image

为什么微软不提供PropertyEquality<T> 这个类呢?
按照上面的逻辑,这个类应该没有很复杂啊,细心的同学可以发现PropertyEquality 大量的使用了反射。每次获取属性的值的时候,都在调用
_PropertyInfo.GetValue(x, null);
可想而知,如果要筛选的记录非常多的话,那么性能无疑会受到影响。
为了提升性能,可以使用表达式树将反射调用改为委托调用,
具体代码如下:

public class FastPropertyComparer<T> : IEqualityComparer<T>
{
    private Func<T, Object> getPropertyValueFunc = null;
    /// <summary>
    /// 通过propertyName 获取PropertyInfo对象
    /// </summary>
    /// <param name="propertyName"></param>
    public FastPropertyComparer(string propertyName)
    {
        PropertyInfo _PropertyInfo = typeof(T).GetProperty(propertyName,
        BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public);
        if (_PropertyInfo == null)
        {
            throw new ArgumentException(string.Format("{0} is not a property of type {1}.",
                propertyName, typeof(T)));
        }
        ParameterExpression expPara = Expression.Parameter(typeof(T), "obj");
        MemberExpression me = Expression.Property(expPara, _PropertyInfo);
        getPropertyValueFunc = Expression.Lambda<Func<T, object>>(me, expPara).Compile();
    }
    #region IEqualityComparer<T> Members
    public bool Equals(T x, T y)
    {
        object xValue = getPropertyValueFunc(x);
        object yValue = getPropertyValueFunc(y);
        if (xValue == null)
            return yValue == null;
        return xValue.E
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 为何Linq的Distinct实在是不给力

相关文章

  • 2017-05-28简单谈谈C#中深拷贝、浅拷贝
  • 2017-05-28c#中利用委托反射将DataTable转换为实体集的代码
  • 2017-05-28理解C#中的枚举(简明易懂)
  • 2017-05-28c#实现KTV点歌系统
  • 2017-05-28C#检测两个矩阵是否相等的方法
  • 2017-05-28C#通过经纬度计算2个点之间距离的实现代码
  • 2017-05-28C#特性-迭代器(上)及一些研究过程中的副产品
  • 2017-05-28C#画笔使用复合数组绘制单个矩形的方法
  • 2017-05-28C#中foreach语句深入研究
  • 2017-05-28Winform让DataGridView左侧显示图片

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C#获取指定目录最后写入时间的方法
    • asp.net中调用oracle存储过程的方法
    • C#算法之全排列递归算法实例讲解
    • 简单的观察者模式示例分享
    • C#使用StreamReader读取文件的方法
    • C#中timer定时器用法实例
    • 关于System.Convert的那些事儿
    • 浅谈C#下winform和JS的互相调用和传参(webbrowser)
    • 深入多线程之:深入生产者、消费者队列分析
    • C#编程中使用ref和out关键字来传递数组对象的用法

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有