当匿名类型遇上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工具看个究竟了。如下图所示:

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

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

时间: 2024-08-09 22:01:47

当匿名类型遇上Distinct的相关文章

【C#复习总结】匿名类型由来

1 属性 这得先从属性开始说,为什么外部代码访问对象内部的数据用属性而不是直接访问呢,这样岂不是更方便一些,但是事实证明直接访问是不安全的.那么,Anders Hejlsberg(安德斯·海尔斯伯格)就为C#加入了属性这种语法糖,用起来跟数据成员一样,但实际上是 setXX()和getXX(),既安全又方便. 属性:是访问对象的首选方式,因为它们禁止外部代码访问对象内部的数据存储机制的实现. public int MyIntProp { get { //property get code } s

定义类+类实例化+属性+构造函数+匿名类型var+堆与栈+GC回收机制+值类型与引用类型

为了让编程更加清晰,把程序中的功能进行模块化划分,每个模块提供特定的功能,而且每个模块都是孤立的,这种模块化编程提供了非常大的多样性,大大增加了重用代码的机会. 面向对象编程也叫做OOP编程 简单来说面向对象编程就是结构化编程,对程序中的变量结构划分,让编程更清晰. 类的概念: 类实际上是创建对象的模板,每个对象都包含数据,并提供了处理和访问数据的方法. 类定义了类的每个对象(称为实例)可以包含什么数据和功能. 类中的数据和函数称为类的成员:数据成员        函数成员 数据成员: 数据成员

编写高质量代码改善C#程序的157个建议——建议26:使用匿名类型存储LINQ查询结果

建议26:使用匿名类型存储LINQ查询结果 从.NET3.0开始,C#开始支持一个新特性:匿名类型.匿名类型有var.赋值运算符和一个非空初始值(或以new开头的初始化项)组成.匿名类型有如下基本特性: 即支持简单类型也指出复杂类型.简单类型必须是一个非空初始值,复杂类型则是一个以new开头的初始化项. 匿名类型的属性是只读的,没有属性设置器,它一旦被初始化就不可更改. 如果两个匿名类型的属性值相同,那么就认为这两个匿名类型相等. 匿名类型可以再循环中用作初始化器. 匿名类型支持智能感知. 匿名

C#超级实用的一种类型—匿名类型

顾名思义 匿名类型就是没有名字的类型.当一个新的匿名对象定义与前面已经存在的类型定义的内部变量类型相同时,编译器就会只生成一个类定义,而不是各一个.匿名类型对象中仍然可以再包含匿名对象. 在C#3.0中允许我们在程序中声明一个临时的类型来存储数据,例如: class Program { static void Main(string[] args) { //声明一个匿名对象,拥有 Name和Age 属性 var obj = new { Name = "Joey", Age = 25 }

如何把匿名类型.GetType()返回的对象传进泛型里面[转]

//怎么取得匿名类型的Type放到 //泛型T当中?? var 匿名 = new { A = 0, B = 1 }; Type t = 匿名.GetType(); //然后下面 var xx = dbContext.Database.SqlQuery<t>("sql"); //就悲剧了 var xx2 = dbContext.Database.SqlQuery<dynamic>("sql"); //xx2有列表,但是都是Object..~~~

理解隐式类型、对象初始化程序和匿名类型

在C# 3.0中,几乎每个新特性都是为LINQ服务的.所以,本文将介绍下面几个在C# 3.0中引入的新特性: 自动实现的属性 隐式类型的局部变量 对象和集合初始化程序 隐式类型的数组 匿名类型 其实这几个特性都是比较容易理解的,对于这几个特性,编译器帮我们做了更多的事情(想想匿名方法和迭代器块),从而简化我们的代码. 自动实现的属性 在C# 3.0以前,当我们定义属性的时候,一般使用下面的代码 public class Book { private int _id; private string

15.C#回顾及匿名类型(八章8.1-8.5)

今天的篇幅应该会很长,除了回顾前面学的一些,还有写一些关于匿名类型的相关知识,总体上对后续的学习很有帮助,学好了,后面更容易理解,不明白的,那就前面多翻几次,看多了总是会理解的.那么,进入正题吧. 自动实现属性 我们的很多工作都是由编译器帮我们去完成,如我们要说的自动实现属性.使用自动实现属性时,C#3执行了一个简单的编译转换,在类的内部生成一个私有的字段,使用不友好的命名(防止命名冲突).在C#2中允许为取值和赋值方法指定不同的访问权限,现在我们还可以创建静态的自动属性. 隐式类型 使用隐式类

当VB遇上C++

最近在学习VB.NET 这块的东西,自然而然就会想到VB.NET与VB6是什么关系? 宏观上来讲就是从基于对象变成了完全的面向对象,因此不能简单的说VB.NET是VB6.0的升级版本.在学习VB.NET之前,已经接触过C++和VB,所以在学习VB.NET的时候总能看到他们的影子,那种似曾相识的感觉让我不得不仰天长叹:这VB.NET简直就是混搭版本的程序设计语言啊! 在1991年Visual Basic1.0诞生以前,开发人员不得不使用C++和Windows系统本身的未成形的程序块,即所谓的Win

看看这个超级实用的一种类型——匿名类型

既然说到匿名类型超级实用,得要找到场景来说服一下,如果大家玩过php,里面有一个万能的关联数组array,任你在关联数组array里面怎么写,都 可以用json_encode来生成json,非常非常的方便. <?php //可以这么写 $arr= array("name"=>"hxc","age"=20,"isMale"=>true); //也可以这么写 $arrayName = array("li