a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 編程 > C# > 正文

為何Linq的Distinct實在是不給力

2020-01-24 03:20:50
字體:
來源:轉載
供稿:網友
假設我們有一個類: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();
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 午夜精品一区二区三区在线 | 天天添夜夜操 | 国产成人免费视频 | 激情欧美一区 | 中文字幕亚洲欧美日韩在线不卡 | 免费成人小视频 | 天天干一干 | 成人免费观看cn | 国产极品一区 | 亚洲精品一区二区三区蜜桃久 | 永久91嫩草亚洲精品人人 | 在线观看日韩av | 亚洲精品三级 | 国产精品呻吟av | 久久精品小视频 | 亚洲视频a | 不卡久久 | 国产黄a三级三级看三级 | 狠狠色伊人亚洲综合成人 | 中文字幕在线精品 | 在线精品亚洲欧美日韩国产 | 91在线看视频 | 国产一级在线观看 | 国产成人精品一区二三区四区五区 | 久久免费视频播放 | 欧美精品久久久久久久久久丰满 | 日本欧美大片 | www.99久久久| 国产精品欧美日韩在线观看 | 91视频播放 | 欧美一级黄色影院 | 男女免费视频 | 国产成人久久精品一区二区三区 | 久久久久久一区 | 91 中文字幕 | 国产成人在线免费观看 | 国产精品久久久99 | 午夜在线免费观看 | 伊人超碰| 欧美在线网站 | 欧美一区2区三区4区公司二百 |