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 ...
随机推荐
- Python的逻辑运算符and小析
近期突然对验证码的识别感兴趣了,然后就研究了一些图像识别和处理的资料,其中有一种图像处理是关于字体的细化和骨架提取的,但是这种算法没有现成的java代码实现,那些号称的java版代码多半都是效果很差或 ...
- 首个攻击该Mac OS系统的恶意软件——KeRanger
首个攻击该Mac OS系统的恶意软件——KeRanger 曾几何时,苹果操作系统一度被人认为是最安全的操作系统.然而近几年,针对苹果系统的攻击日益增多,影响范围也越来越大.无独有偶,近日,苹果Mac ...
- UVA 11992 Fast Matrix Operations (二维线段树)
解法:因为至多20行,所以至多建20棵线段树,每行建一个.具体实现如下,有些复杂,慢慢看吧. #include <iostream> #include <cstdio> #in ...
- redis 一二事 - 搭建集群缓存服务器
在如今并发的环境下,对大数据量的查询采用缓存是最好不过的了,本文使用redis搭建集群 (个人喜欢redis,对memcache不感冒) redis是3.0后增加的集群功能,非常强大 集群中应该至少有 ...
- linux下查找某个目录下包含某个字符串的文件
有时候要找一些字符串,但是又不知道在哪个文件,只记得一些字符串 那么如何在linux下寻找包含某段文字的文件呢? 强大的find命令可以帮你完成不可能的任务. 比如我只记得我的程序里包含唯一的字符串“ ...
- [原创]CI持续集成系统环境--Gitlab+Gerrit+Jenkins完整对接
近年来,由于开源项目.社区的活跃热度大增,进而引来持续集成(CI)系统的诞生,也越发的听到更多的人在说协同开发.敏捷开发.迭代开发.持续集成和单元测试这些拉风的术语.然而,大都是仅仅听到在说而已,国内 ...
- f2fs解析(四)f2fs的extent特性
extent的意思是“程度”,但是我还是搞不清楚要如何把“程度”和我理解的extent联系到一起. 文件的偏移和page-cache的映射关系体现在address space 中的一颗基数树上:当基数 ...
- slatsatck file模块2种写法及系统初始化
一 . lamp搭建 file2种写法 saltstack--一键yum lamp:---请注意重点: http://www.blogs8.cn/posts/WLjId80 知识点: 文件的2种写 ...
- C语言 预处理二(宏定义--#define)
//#define 宏定义(宏定义一般大写) //知识点一-->#define的作用域:从#define开始,从上往下,如果遇到#undef就到#undef处结束,如果没有就是作用于当前整个文件 ...
- 解决网站在负载均衡环境下SESSION丢失的问题
在WEB场中,动态网页往往会因为几台主机做了负载而产生SESSION丢失的问题,网上也有很多的介绍,我这里只将我经历的过程给大家分享一下: 系统要运行在负载平衡的 Web 场环境中,而系统配置文件 ...