当匿名类型遇上Distinct

首先定义一个简单类,并重写ToString方法。

public class CommidityFilter
    {
        public string Property { get; set; }
        public string Characterist { get; set; }

        public override string ToString()
        {
            return string.Format("Property:{0},Characterist:{1}", this.Property, this.Characterist);
        }
    }

然后手动生成一个IEnumerable<CommidityFilter>集合。

private static IEnumerable<CommidityFilter> GetCommidityFilters()
        {
            var result = new List<CommidityFilter>
                {
                    new CommidityFilter {Property = "Size",Characterist = "L"},
                    new CommidityFilter {Property = "Size",Characterist = "L"},
                    new CommidityFilter {Property = "Size",Characterist = "XL"},
                    new CommidityFilter {Property = "Color",Characterist = "Red"},
                    new CommidityFilter {Property = "Color",Characterist = "Yellow"},
                    new CommidityFilter {Property = "Color",Characterist = "Red"}
                };

            return result;
        }

现在要做的是对整个集合进行过滤,去掉重复的CommidityFilter,通常都会用Distinct扩展方法。要对CommidityFilter集合去掉重复项,一共有两种方法。

1:重写CommidityFilter的Equals、GetHashCode方法。

2:Distinct方法指定一个实现了IEqualityComparer接口的对象。

这里我们采用第二种方法,首先来实现CommidityFilterComparer

public class CommidityFilterComparer : IEqualityComparer<CommidityFilter>
    {
        public bool Equals(CommidityFilter x, CommidityFilter y)
        {
            if (x == null || y == null)
                return false;
            return String.Compare(x.Property, y.Property) == 0 && String.Compare(x.Characterist, y.Characterist) == 0;
        }

        public int GetHashCode(CommidityFilter obj)
        {
            return obj.Property.GetHashCode() ^ obj.Characterist.GetHashCode();
        }
    }

然后实现去掉重复项的代码:

var result = GetCommidityFilters();
var filters = result.Distinct(new CommidityFilterComparer()).ToArray();
Array.ForEach(filters, Console.WriteLine);

输出的结果如下:

Property:Size,Characterist:L

Property:Size,Characterist:XL

Property:Size,Characterist:Red

Property:Size,Characterist:Yellow

 

上面完美的实现了想要的结果,但是开发经常遇到的情况是GetCommidityFilters方法返回的集合中的CommidityFilter可能不只是Property,Characterist两个属性,比方还有其他的OtherProperty属性。而前端的ViewModel只需要去掉重复项后Property,Characterist两个属性。在这种情况下,通常会选择用匿名类型。现在来重新定义下CommidityFilter类、以及GetCommidityFilters方法。

public class CommidityFilter
    {
        public string Property { get; set; }
        public string Characterist { get; set; }
        public string OtherProperty { get; set; }

        public override string ToString()
        {
            return string.Format("Property:{0},Characterist:{1}", this.Property, this.Characterist);
        }
    }
private static IEnumerable<CommidityFilter> GetCommidityFilters()
        {
            var result = new List<CommidityFilter>
                {
                    new CommidityFilter {Property = "Size",Characterist = "L",OtherProperty = "A"},
                    new CommidityFilter {Property = "Size",Characterist = "L",OtherProperty = "B"},
                    new CommidityFilter {Property = "Size",Characterist = "XL",OtherProperty = "C"},
                    new CommidityFilter {Property = "Color",Characterist = "Red",OtherProperty = "D"},
                    new CommidityFilter {Property = "Color",Characterist = "Yellow",OtherProperty = "E"},
                    new CommidityFilter {Property = "Color",Characterist = "Red",OtherProperty = "F"}
                };

            return result;
        }

接下来,再来实现去掉重复项的代码。

var result = GetCommidityFilters();
            var filters = result.Select(e => new
                {
                    Property = e.Property, 
                    Characterist = e.Characterist
                }).Distinct().ToArray();
            Array.ForEach(filters, Console.WriteLine);

输出的结果如下:

{Property = Size,Characterist = L}

{Property = Size,Characterist = XL}

{Property = Size,Characterist = Red}

{Property = Size,Characterist = Yellow}

在上面实现的去重复项代码中,并没有为Distinct扩展方法指定一个实现了IEqualityComparer接口的对象,还是很完美的去掉的重复项。这是为什么呢?只能借助于IL DASM工具看个究竟了。如下图所示:

20141231163005

原来C#编译器会在背后默默的给所有的匿名类型重写Equals,GetHashCode,ToString三个方法,也就是说对匿名类型的集合使用Distinct过滤重复项,默认就是上面提到的第一种方法。

2014年就要过去了,我的2014相比2013年来说过的有点平庸,在最后一天才写了这年的第一篇随笔,希望2015年,我能过得轰轰烈烈点。

posted @ 2014-12-31 16:36  supperwu  阅读(1285)  评论(0编辑  收藏  举报