• 为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是要用来判断去重的唯一值
    

      

  • 相关阅读:
    应用实例:用户登录(2009.10.23)
    ASP.NET学习笔记:服务器控件 (2009.11.9)
    小实例:模拟电话簿
    用Iframe实现左边TreeView导航,右边显示相应内容的布局
    HTML&CSS&JaveScript学习笔记(2009.11.19)
    C#中问号(?)的用法
    GridView的简单分页等
    GridView正反双向排序
    代码理解(2009.11.20)
    ASP.NET学习笔记:数据库操作 (2009.11.10)
  • 原文地址:https://www.cnblogs.com/saving/p/5596486.html
Copyright © 2020-2023  润新知