购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

建议26:使用匿名类型存储LINQ查询结果

从.NET 3.0开始,C#开始支持一个新特性:匿名类型。匿名类型由var、赋值运算符和一个非空初始值(或以new开头的初始化项)组成。匿名类型有如下的基本特性:

❑既支持简单类型也支持复杂类型。简单类型必须是一个非空初始值,复杂类型则是一个以new开头的初始化项;

❑匿名类型的属性是只读的,没有属性设置器,它一旦被初始化就不可更改;

❑如果两个匿名类型的属性值相同,那么就认为两个匿名类型相等;

❑匿名类型可以在循环中用作初始化器;

❑匿名类型支持智能感知;

❑还有一点,虽然不常用,但是匿名类型确实也可以拥有方法。

那么,既然已经有了普通的自定义类型(如类型Person),为什么我们还需要匿名类型呢?考虑如下的场景:将Person或Person的相关类(如Company)从数据库中取出来之后,我们需要将Person中的属性Name和根据CompanyID对应起来的Company的属性Name关联起来,形成一个新的类型。这个新的类型也许用于某个UI控件的绑定源,也许用于某个特殊算法的输入。总之,数据库中的格式一旦设计完毕并投入使用,很少会有变动,但是需求却是千变万化的,实际需求需要创建很多这样的临时类型。如果这类临时类型全部使用普通的自定义类型,代码将会膨胀起来而变得难以维护。这个时候,匿名类型就派上用场了。

在类型仅仅被当前的代码使用,或者被用于存储某种查询结果的场景中,匿名类型将大有用途。匿名类型的这个特点使它成为保存LINQ查询结果的最佳搭档。

假设数据库中Company存储的记录如表2-1所示。

表2-1 Company 记录表

数据库中Person存储的记录如表2-2所示。

表2-2 Person 记录表

按照传统的做法,Company记录表和Person记录表在应用程序中都有对应的实体类。我们要创建的临时对象包括PersonName和CompanyName,满足该需求的一个示例如下:


static void Main(string[]args)

{

//为了演示需要,companyList并不从数据库读取,而是直接赋值

List<Company>companyList=new List<Company>()

{

new Company(){ComanyID=0,Name="Micro"},

new Company(){ComanyID=1,Name="Sun"}

};

//为了演示需要,personList并不从数据库读取,而是直接赋值

List<Person>personList=new List<Person>()

{

new Person(){Name="Mike",CompanyID=1},

new Person(){Name="Rose",CompanyID=0},

new Person(){Name="Steve",CompanyID=1}

};

var personWithCompanyList=from person in personList

join company in companyList on person.CompanyID equals company.ComanyID

select new{PersonName=person.Name,CompanyName=company.Name};

foreach(var item in personWithCompanyList)

{

Console.WriteLine(string.Format("{0}\t:{1}",

item.PersonName,item.CompanyName));

}

}

}

class Person

{

public string Name{get;set;}

public int CompanyID{get;set;}

}

class Company

{

public int ComanyID{get;set;}

public string Name{get;set;}

}


输出为:


Mike:Sun

Rose:Micro

Steve:Sun


这段代码的核心语句见代码黑体部分。

new之前的代码是LINQ关键字,new之后的代码就是匿名类型的初始化项。该匿名类型包含两个属性:PersonName和CompanyName。将匿名类型中对应的属性重命名在有些时候是件很有必要的事情。本例中,如果不将Person中的Name重命名为PersonName,以及将Company中的Name重命名为CompanyName,会给我们的实际编码造成一定的困扰。

匿名类型也派生自Object,查看上面代码的IL代码我们知道,匿名类型会在IL中发出一个类(也称为一个投影),如图2-6所示。

图2-6 匿名类型的IL结构

非匿名类型包括的Equals、GetHashcode、ToString等方法匿名类型都有。并且,编译器为我们重载了ToString方法,它返回的是类型的属性及对应的值。如果为上面的循环输出部分增加一条语句:


Console.WriteLine(item.ToString());


那么代码的输出将会变为:


Mike:Sun

{PersonName=Mike,CompanyName=Sun}

Rose:Micro

{PersonName=Rose,CompanyName=Micro}

Steve:Sun

{PersonName=Steve,CompanyName=Sun} kuHu8FfwvTzCYIORrmy1R76c207d9gKWD+YgQekYck4gIA2Yag95nv+UDwq317WT


点击中间区域
呼出菜单
上一章
目录
下一章
×

打开