Linq之隐式类型、自动属性、初始化器、匿名类
目录
写在前面
上篇文章是本系列的小插曲,也是在项目中遇到,觉得有必要总结一下,就顺手写在了博客中,也希望能帮到一些朋友。本文将继续介绍linq系列的基础知识,隐式类型,自动属性,初始化器,匿名类的相关概念,这些内容也许与linq相关也许不相关,但还是放一起总结吧,也算是复习了。部分内容通过反编译的方式一探究竟。
系列文章
隐式类型
先看看Msdn上对隐式类型的简单定义
从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型 var。 隐式类型的本地变量是强类型变量(就好像您已经声明该类型一样),但由编译器确定类型。
一个例子
static void Main(string[] args)
{
//隐式类型 implicitly typed
var i = ;
//显示类型 explicitly typed
int j = ;
Console.WriteLine(i.ToString());
Console.WriteLine(j.ToString());
Console.ReadKey();
}
从上面msdn上的解释,隐式类型本地变量是强类型的,由编译器确定类型,那么我们编译一下该项目,然后使用ILspy反编译查看该程序集,看看是不是将i定义为了int类型,以解心中的迷惑。

你会发现,在编译之后,变量该是什么类型就是什么类型,感觉好牛逼的样子。
那到底那些情况下可以用var?在不知道返回的到底是什么类型的时候,var的用处非常大,还有就是如果返回值类型非常长,写var也是比较轻松的,但有的时候你想真真切切看到到底是什么类型的时候,这个时候就不要用var了。再看一个例子:
//该方式返回一个匿名类,这个时候不知道用什么类型来接受,就用var
var custQuery = from cust in customers
where cust.City == "Phoenix"
select new { cust.Name, cust.Phone };
如果要遍历上面的结果,此时也必须是var,也就有了类似下面的代码
foreach(var item in custQuery)
{
//逻辑代码
}
自动属性
首先看MSDN的说法
在 C# 3.0 和更高版本中,当属性的访问器中不需要其他逻辑时,自动实现的属性可使属性声明更加简洁。 客户端代码还可通过这些属性创建对象。
这就话有点意思,“当属性的访问器中不需要其他逻辑时”,那这就话另外一个意思是,如果访问器中需要其他逻辑时,就不使用自动属性。
一个例子
如果有这样一个Person类,对年龄加了限制,年龄不得小于0,不得大于100,此时如果使用自动属性,逻辑无法添加了。如:
class Person
{
private int age;
public int Age
{
set
{
if (age > && age <= )
{
age = value;
}
else
{
throw new Exception("年龄必须在1~100范围内");
}
}
get { return age; }
}
public string Name { set; get; }
}
那么定义的自动属性,编译器又替咱们做了那些工作呢?反编译一下看个究竟

看来编译器为咱们做了很多工作。
初始化器
最常用到的初始化器有对象初始化器和集合初始化器,数组初始化器。还以上面的Person类为例:
c#3.0之前的做法是
Person p = new Person();
p.Name = "wolfy";
p.Age = ;
现在又多了一种新的玩法,对象初始化器,你现在可以这样写:
在写完大括号后,只需要一个空格,所有的属性就会智能提示出来,而且编写一个就会少一个属性,避免了多个属性的混淆。


相比之前的做法

如果一个类的字段很多,由于基类object的属性及方法的干扰,上下键的去找属性,实在是太麻烦了。通过对象初始化器,你写一个少一个,也避免出现了少为属性赋值的情况了。
那么对象初始化器,编译器又为我们做了什么?同样还是反编译一下看一个究竟
代码:
Person p = new Person() { Name="wolfy", Age= };
反编译查看的结果:

集合初始化器
代码
List<Person> persons = new List<Person>()
{
new Person(){ Age=, Name="张三"},
new Person(){Age=,Name="李四"}
};
反编译查看的结果:

的确够智能了,不能忍了,编译器替你一个一个去Add了。
数组呢?
代码
Person[] persons = new Person[]{
new Person(){ Name="张三", Age=},
new Person(){ Name="李四" , Age=}
};

看来内部并没什么变化。
匿名类
同样查看MSDN的定义
匿名类型提供了一种方便的方法,可用来将一组只读属性封装到单个对象中,而无需首先显式定义一个类型。 类型名由编译器生成,并且不能在源代码级使用。 每个属性的类型由编译器推断。
匿名类型通常用在查询表达式的 select 子句中,以便返回源序列中每个对象的属性子集。
匿名类型包含一个或多个公共只读属性。 包含其他种类的类成员(如方法或事件)为无效。 用来初始化属性的表达式不能为 null、匿名函数或指针类型。
有了匿名类类型可以这样写代码
var v = new { age = , name = "wolfy" };
Console.WriteLine(v.age + " " + v.name);
反编译看一下IL

通过上面IL,也可以说明为什么不能赋值为null,这样编译器就无法推断它到底是什么类型了。

匿名类的属性是只读的,无法修改

如果不为匿名类中的属性指定名称,则采用初始化这些属性时所采用的属性的名称作为匿名类的属性名称,看一个例子

通常,当你使用匿名类型来初始化变量时,可以通过使用 var 将变量作为隐式键入的本地变来变量进行声明。 类型名称无法在变量声明中给出,因为只有编译器能访问匿名类型的基础名称。
一个例子
//可通过将隐式键入的本地变量与隐式键入的数组相结合创建匿名键入的元素的数组
var anonArray = new[] { new { name = "apple", diam = }, new { name = "grape", diam = }};
匿名类型是直接从对象派生的类类型,并且其无法强制转换为除对象外的任意类型。 虽然你的应用程序不能访问它,编译器还是提供了每一个匿名类型的名称。 从公共语言运行时的角度来看,匿名类型与任何其他引用类型没有什么不同。
如果程序集中的两个或多个匿名对象初始值指定了属性序列,这些属性采用相同顺序且具有相同的名称和类型,则编译器将对象视为相同类型的实例。 它们共享同一编译器生成的类型信息。
无法将字段、属性、时间或方法的返回类型声明为具有匿名类型。 同样,你不能将方法、属性、构造函数或索引器的形参声明为具有匿名类型。 要将匿名类型或包含匿名类型的集合作为参数传递给某一方法,可将参数作为类型对象进行声明。 但是,这样做会使强类型化作用无效。 如果必须存储查询结果或者必须将查询结果传递到方法边界外部,请考虑使用普通的命名结构或类而不是匿名类型。
由于匿名类型上的 Equals 和 GetHashCode 方法是根据方法属性的 Equals 和 GetHashCode 定义的,因此仅当同一匿名类型的两个实例的所有属性都相等时,这两个实例才相等。
总结
本文通过反编译的方式,学习了隐式类型,自动属性,初始化器一级匿名类型的相关概念。常见的c#语法糖,在一起总结了。
参考文章
http://msdn.microsoft.com/zh-cn/library/bb383973.aspx
http://msdn.microsoft.com/zh-cn/library/bb384054.aspx
http://msdn.microsoft.com/zh-cn/library/bb397696.aspx
Linq之隐式类型、自动属性、初始化器、匿名类的更多相关文章
- linq和隐式类型var
隐式类型 var 强类型,声明的时候必须给变量赋值,编译器会根据值来确定其类型.只能出现在局部变量或脚本代码中. 使用范围: 简单类型:如int string等 复杂类型:如数组.类等 逻辑语句:fo ...
- C#3.0新特性:隐式类型、扩展方法、自动实现属性,对象/集合初始值设定、匿名类型、Lambda,Linq,表达式树、可选参数与命名参数
一.隐式类型var 从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,编译器自动推断类型. 1.var类型的局部变量必须赋予初始值,包括匿名 ...
- C#3.0新增功能03 隐式类型本地变量
连载目录 [已更新最新开发文章,点击查看详细] 从 Visual C# 3.0 开始,在方法范围内声明的变量可以具有隐式“类型”var. 隐式类型本地变量为强类型,就像用户已经自行声明该类型,但 ...
- .NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器
开篇:在日常的.NET开发学习中,我们往往会接触到一些较新的语法,它们相对以前的老语法相比,做了很多的改进,简化了很多繁杂的代码格式,也大大减少了我们这些菜鸟码农的代码量.但是,在开心欢乐之余,我们也 ...
- C#的隐式类型、匿名类型、自动属性、初始化器
1.隐式类型 1)源起 在隐式类型出现之前,我们声明一个变量时,需要为它指定相应的类型,甚至在foreach一个集合的时候,也要为遍历的集合元素,指定变量的类型,隐式类型出现后,程序员就不用再做这个工 ...
- C#中的自动属性、隐式类型var、对象初始化器与集合初始化器、扩展方法
1.自动属性(Auto-Implemented Properties) //以前的写法 .net2.0 private string _userName; public string UserName ...
- C#语法糖之第一篇:自动属性&隐式类型
今天给大家分享一下C#语法糖的简单的两个知识点吧. 自动属性:在 C# 4.0 和更高版本中,当属性的访问器中不需要其他逻辑时,自动实现的属性可使属性声明更加简洁. 客户端代码还可通过这些属性创建对象 ...
- c#4.5新语法--自动属性和隐式类型
1.自动属性 自动属性是c#中属性定义的两种形式的一种:传统属性定义.自动属性. 1.1 传统属性定义 private int _age; public int ...
- C#中的隐式类型var——详细示例解析
从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,它的具体类型由编译器根据上下文推断而出. 下面就让我来总结下隐式类型的一些特点: 1.va ...
随机推荐
- Linux 学习之DNS服务器
概念: DNS:Domain Name System 域名系统 FQDN:Fully Qualified Domain Name 完整主机名 正向解析:由主机名查IP地址 SOA:开始验证(Start ...
- SharpDX之Direct2D教程II——加载位图文件和保存位图文件
本系列文章目录: SharpDX之Direct2D教程I——简单示例和Color(颜色) 绘制位图是绘制操作的不可缺少的一部分.在Direct2D中绘制位图,必须先利用WIC组件将位图加载到内存中,再 ...
- A*算法详解 BZOJ 1085骑士精神
转载1:A*算法入门 http://www.cppblog.com/mythit/archive/2009/04/19/80492.aspx 在看下面这篇文章之前,先介绍几个理论知识,有助于理解A*算 ...
- Zero
Zero是我的极品现任BOSS曾用过的QQ昵称.那时候,我正跟京姑娘闹七年之痒,甩她而去赋闲在老家.Zero通过朋友介绍,看了我几篇零散的博客,就给我打电话,让我过来聊聊.本来我跟京姑娘也没有大矛盾, ...
- css reset重置样式有那么重要吗?
在以前写html代码的时候,一般都会在head里添加重置样式reset.css,其内容如下: @charset "utf-8"; html, body, div, span, ap ...
- sql 入门经典(第五版) Ryan Stephens 学习笔记 (第六,七,八,九,十章,十一章,十二章)
第六章: 管理数据库事务 事务 是 由第五章 数据操作语言完成的 DML ,是对数据库锁做的一个操作或者修改. 所有事务都有开始和结束 事务可以被保存和撤销 如果事务在中途失败,事务中的任何部分都不 ...
- AC日记——铺地毯 洛谷 P1003(水水水水水~)
题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小到大的顺序平行于 ...
- Eclipse去除JavaScript验证错误
这篇文章主要是对Eclipse去除js(JavaScript)验证错误进行了介绍.在Eclipse中,js文件常常会报错.可以通过如下几个步骤解决 第一步: 去除eclipse的JS验证: 将wind ...
- 实例化Model的三种方式
- MVC3中,在control里面三种Html代码输出形式
MVC3中,在control里面三种Html代码输出形式:ViewData["msg"] = "<br /> Title <br />" ...