C# 中distinct的使用


假設我們有一個類: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.Equals(yValue); } public int GetHashCode(T obj) { object propertyValue = getPropertyValueFunc(obj); if (propertyValue == null) return 0; else return propertyValue.GetHashCode(); } #endregion }

 

可以看到現在獲取值只需要getPropertyValueFunc(obj) 就可以了。

使用的時候:

var distinctProduct = products.Distinct(new FastPropertyComparer<Product>("Id")).ToList();


http://www.cnblogs.com/joyang/p/5702472.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM