linq中distinct扩展,快速创建IComparer<T> 的实例

1.功能描述:要实现这么一个功能:取出下载前10名的应用,且10个应用分别属于不同的类。


2.问题描述:因为采用NoSql存数,数据已经存在list实体中,所以打算采用linq中distinct的方法实现它,实体类结构为:
public class KBase
{
   public int kId {get;set}
   public string SName {get;set}
   public int CId {get;set}    //类别Id
 .
 .
 .
};
list实现中有40条数据(存在CId重复记录),数据较多,省去不列举出来,实现如下:
var distinctApkBase = KBase.distinct();
结果出来没得到我想要的,重复cId的记录还是存在,后来才发现Distinct默认比较的是KBase对象的引用

接续使用Distinct方法的另一个重载:
public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer);该重载接收一个IEqualityComparer的参数。

假设要按Id来筛选,那么应该新建类CategoryIdComparer 内容如下:

public class CategoryIdComparer : IEqualityComparer<KBase>
{
    public bool Equals(KBase x, KBase y)
    {
        if (x == null)
            return y == null;
        return x.CId == y.CId;
    }

    public int GetHashCode(KBase obj)
    {
        if (obj == null)
            return 0;
        return obj.CategoryId.GetHashCode();
    }
}
使用的时候,只需要
var distinctKBase = KBase.Distinct(new CategoryIdComparer());结果是可以过滤重复的cId了,但按照这样的方式,如果我要按SName进行distinct的话,又要重新写一个类SNameComparer

3.解决办法:后面根据net 中 IEqualityComparer<T> 和 IComparer<T>整了一个类以实现快速创建IComparer<T> 的实例:
public static class ComparisonHelper<T>
{
    public static IComparer<T> CreateComparer<V>(Func<T, V> keySelector)
    {
        return new CommonComparer<V>(keySelector);
    }
    public static IComparer<T> CreateComparer<V>(Func<T, V> keySelector, IComparer<V> comparer)
    {
        return new CommonComparer<V>(keySelector, comparer);
    }

    class CommonComparer<V> : IComparer<T>
    {
        private Func<T, V> keySelector;
        private IComparer<V> comparer;

        public CommonComparer(Func<T, V> keySelector, IComparer<V> comparer)
        {
            this.keySelector = keySelector;
            this.comparer = comparer;
        }
        public CommonComparer(Func<T, V> keySelector)
            : this(keySelector, Comparer<V>.Default) //Comparer<V> 类和它的 Default 属性是关键
        { }

        public int Compare(T x, T y)
        {
            return comparer.Compare(keySelector(x), keySelector(y));
        }
    }
}
使用方法:
var comparer1 = Comparison<ApkBase>.CreateComparer(p => p.ApkId);
var comparer2 = Comparison<ApkBase>.CreateComparer(p => p.ApkSoftName);
var comparer3 = Comparison<ApkBase>.CreateComparer(p => p.CategoryId);

posted on 2012-11-15 16:45  cyz_393  阅读(219)  评论(0)    收藏  举报