【转】编写高质量代码改善C#程序的157个建议——建议26:使用匿名类型存储LINQ查询结果
建议26:使用匿名类型存储LINQ查询结果
从.NET3.0开始,C#开始支持一个新特性:匿名类型。匿名类型有var、赋值运算符和一个非空初始值(或以new开头的初始化项)组成。匿名类型有如下基本特性:
- 即支持简单类型也指出复杂类型。简单类型必须是一个非空初始值,复杂类型则是一个以new开头的初始化项。
- 匿名类型的属性是只读的,没有属性设置器,它一旦被初始化就不可更改。
- 如果两个匿名类型的属性值相同,那么就认为这两个匿名类型相等。
- 匿名类型可以再循环中用作初始化器。
- 匿名类型支持智能感知。
- 匿名类型可以拥有方法。
在类型仅仅被当前的代码使用,或者被用于存储某种查询结果的场景中,匿名类型将大有用途。匿名类型是保存LINQ查询结果的最佳搭档。
如下场景:
将Person或Person相关类(如Company)从数据库中取出来,我们需要将Person中的属性Name和根据CompanyID对应起来的Company的属性Name联系起来,形成一个新的类型。这个新的类型也许用于某个UI控件的绑定源,也许用于某个特殊算法的输入。总之,数据库中的格式一旦设计完毕并投入使用,很少会有变动,但是需求却千变万化,实际需求需要创建很多这样的临时类型。如果这临时类型全部使用普通的自定义类型,代码将会膨胀起来变得难以维护。这个时候,匿名类型就派上用场了。
class Program { 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
查看IL代码,可以看见匿名类型在IL中会生成一个类(也称为一个投影)
非匿名类型包括的Equals、GetHashcode、ToString等方法匿名类型都有。并且编译器为我们重载了ToString方法,它返回的是类型的属性即对应的值。
foreach (var item in personWithCompanyList) { Console.WriteLine(item.ToString()); }
输出的结果为:
{ PersonName = Mike, CompanyName = Sun }
{ PersonName = Rose, CompanyName = Micro }
{ PersonName = Steve, CompanyName = Sun }
转自:《编写高质量代码改善C#程序的157个建议》陆敏技
鹰击长空,鱼翔浅底