C# 中distinct的使用

來源:互聯網
上載者:User

標籤:stat   products   委託   指定   調用   tin   ring   重寫   null   

假設我們有一個類: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 的結果是:

 

因為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());

結果如下:

 

現在假設我們要 按照 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"));

 

結果如下:

 

為什麼微軟不提供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

C# 中distinct的使用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.