zoukankan      html  css  js  c++  java
  • 为Distinct准备的通用对比器

    使用Linq过滤重复对象的时候,我们使用Distinct。

    但是Distinct对int long等值类型才有效果,对于对象我们需要自己写个对象。 

    以下利用泛型封装了两个类:

    CommonComparer<T>

    public class CommonComparer<T> : IEqualityComparer<T>
        {
            Func<T, string> GetStrigPropertyValueFunc;
            Func<T, int>    GetInt32PropertyValueFunc;
            Func<T, long>   GetInt64PropertyValueFunc;
    
            public CommonComparer(string propertyName)
            {
                var tType = typeof(T);
                PropertyInfo propertyInfo = tType.GetProperty(propertyName);
    
                ParameterExpression pExpress = Expression.Parameter(tType);
                MemberExpression bodyExpress = Expression.Property(pExpress, propertyInfo);
    
                switch (propertyInfo.PropertyType.Name)
                {
                    case "Int32":
                        GetInt32PropertyValueFunc = Expression.Lambda<Func<T, int>>(bodyExpress, pExpress).Compile();
                        break;
                    case "Int64":
                        GetInt64PropertyValueFunc = Expression.Lambda<Func<T, long>>(bodyExpress, pExpress).Compile();
                        break;
                    case "String":
                        GetStrigPropertyValueFunc = Expression.Lambda<Func<T, string>>(bodyExpress, pExpress).Compile();
                        break;
                    default: throw new NotSupportedException("对比器只支持int32、int64、String");
                }
            }
    
            public bool Equals(T x, T y)
            {
                if (GetStrigPropertyValueFunc != null)
                {
                    var xValue = GetStrigPropertyValueFunc(x);
                    var yValue = GetStrigPropertyValueFunc(y);
    
                    if (xValue == null) return yValue == null;
                    return xValue.Equals(yValue);
                }
                else if (GetInt32PropertyValueFunc != null)
                {
                    var xValue = GetInt32PropertyValueFunc(x);
                    var yValue = GetInt32PropertyValueFunc(y);
    
                    if (xValue == null) return yValue == null;
                    return xValue.Equals(yValue);
                }
                else if (GetInt64PropertyValueFunc != null)
                {
                    var xValue = GetInt64PropertyValueFunc(x);
                    var yValue = GetInt64PropertyValueFunc(y);
    
                    if (xValue == null) return yValue == null;
                    return xValue.Equals(yValue);
                }
    
                throw new NotSupportedException("没找到支持的委托类型");
            }
    
            public int GetHashCode(T obj)
            {
                if (GetStrigPropertyValueFunc != null)
                {
                    var value = GetStrigPropertyValueFunc(obj);
                    if (obj == null) return 0;
    
                    return value.GetHashCode();
                }
                else if (GetInt32PropertyValueFunc != null)
                {
                    var value = GetInt32PropertyValueFunc(obj);
                    if (obj == null) return 0;
    
                    return value.GetHashCode();
                }
                else if (GetInt64PropertyValueFunc != null)
                {
                    var value = GetInt64PropertyValueFunc(obj);
                    if (obj == null) return 0;
    
                    return value.GetHashCode();
                }
    
                return 0;
            }
        }
    

      

    ReflectCommonComparer<T>

     public class ReflectCommonComparer<T> : IEqualityComparer<T>
        {
            string PropertyName;
    
            public ReflectCommonComparer(string propertyName)
            {
                PropertyName = propertyName;
            }
    
            object GetPropertyValue(T x)
            {
                PropertyInfo propertyInfo = typeof(T).GetProperty(PropertyName);
                return propertyInfo.GetValue(x);
            }
    
            public bool Equals(T x, T y)
            {
                var xValue = GetPropertyValue(x);
                var yValue = GetPropertyValue(y);
    
                if (xValue == null) return yValue == null;
                return xValue.Equals(yValue);
            }
    
            public int GetHashCode(T obj)
            {
                var value = GetPropertyValue(obj);
                if (obj == null) return 0;
    
                return value.GetHashCode();
            }
        }
    

      

    CommonComparer利用的是表达式树来实现的,ReflectCommonComparer是利用反射来实现的。网络上说利用的是表达式树来实现比反射更快。

    我做了简单的时间测试,以下是截图:

    1000次循环对比,反射更快呀

    十万次对比,也是反射的比较快呀。

    有可能是我写的表达式树有问题。 有空再去试试。

    ---

    我把去重的数据量变多了之后的对比:

    十万次,表达式树更快了。

    我的结论是,去重的数据量多的话就用表达式树,少的话就用反射。大概超过80就需要用表达式树了。

    因此以上还可以进一步分装。

    public static class LinqExtension
        {
            public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source, string propertyName)
            {
                if (source.Count() > 80)
                    return source.Distinct(new CommonComparer<T>(propertyName));
                else
                    return source.Distinct(new ReflectCommonComparer<T>(propertyName));
            }
        }
    

      使用

    var newList = list.Distinct("id").ToList(); // id是要用来判断去重的唯一值
    

      

  • 相关阅读:
    Nginx配置文件nginx.conf中文详解
    Linux安装nginx
    熊猫TV游戏直播教程-OBS篇
    Mac下MySQL卸载方法
    sphinx 1.10-实时索引 api
    freebsd 国内相当快的ports源地址
    Springboot框架中如何读取位于resource资源中的properties配置文件,并将配置文件中的键对应的值赋值到目标bean中?
    分析Jedis源码实现操作非关系型数据库Redis
    分析线程池源码测试线程池
    socket简单示例实现从服务器拷贝文件到客户端
  • 原文地址:https://www.cnblogs.com/saving/p/5596486.html
Copyright © 2011-2022 走看看