源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

为何Linq的Distinct实在是不给力

  • 时间:2020-05-31 17:25 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:为何Linq的Distinct实在是不给力
[b]假设我们有一个类:Product [/b] public class Product {     public string Id { get; set; }     public string Name { get; set; } } [b]Main函数如下: [/b]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 的结果是: [img]http://files.jb51.net/file_images/article/201305/20130513174443157.png[/img] 因为Distinct 默认比较的是Product对象的引用,所以返回4条数据。 [b]那么如果我们希望返回Id唯一的product,那么该如何做呢? [/b]  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()); 结果如下: [img]http://files.jb51.net/file_images/article/201305/20130513174443158.png[/img] 现在假设我们要 按照 Name来筛选重复呢? 很明显,需要再添加一个类ProductNameComparer. [b]那能不能使用泛型类呢?? [/b]新建类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")); 结果如下: [img]http://files.jb51.net/file_images/article/201305/20130513174443159.png[/img] 为什么微软不提供PropertyEquality<T> 这个类呢? 按照上面的逻辑,这个类应该没有很复杂啊,细心的同学可以发现PropertyEquality 大量的使用了反射。每次获取属性的值的时候,都在调用 [b]_PropertyInfo.GetValue(x, null); [/b]可想而知,如果要筛选的记录非常多的话,那么性能无疑会受到影响。 为了提升性能,可以使用表达式树将反射调用改为委托调用, 具体代码如下: 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.Equals(yValue);     }     public int GetHashCode(T obj)     {         object propertyValue = getPropertyValueFunc(obj);         if (propertyValue == null)             return 0;         else             return propertyValue.GetHashCode();     }     #endregion } 可以看到现在获取值只需要[b]getPropertyValueFunc(obj)[/b] 就可以了。 [b]使用的时候: [/b]var distinctProduct = products.Distinct(new FastPropertyComparer<Product>("Id")).ToList();
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部