.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

时间:2022-08-10 03:36:46

开篇:在日常的.NET开发学习中,我们往往会接触到一些较新的语法,它们相对以前的老语法相比,做了很多的改进,简化了很多繁杂的代码格式,也大大减少了我们这些菜鸟码农的代码量。但是,在开心欢乐之余,我们也不禁地对编译器内部到底为我们做了哪些事儿而感到好奇?于是,我们就借助反编译神器,去看看编译器到底做了啥事!其实本篇中很多都不算新语法,对于很多人来说可能都是接触了很久了,这里主要是针对.NET的老版本来说,是一个“相对”的新语法。

/* 新语法索引 */

1.自动属性 Auto-Implemented Properties
2.隐式类型 var
3.参数默认值 和 命名参数
4.对象初始化器 与 集合初始化器 { }

一、自动属性探秘:[ C# 3.0/.Net 3.x 新增特性 ]

1.1 以前的做法:先写私有变量,再写公有属性

    public class Student
{
private Int32 _id; public Int32 Id
{
get { return _id; }
set { _id = value; }
}
private string _name; public string Name
{
get { return _name; }
set { _name = value; }
}
private Int16 _age; public Int16 Age
{
get { return _age; }
set { _age = value; }
}
}

1.2 现在的做法:声明空属性

    public class Person
{
public Int32 ID { get; set; }
public string Name { get; set; }
public Int16 Age { get; set; }
}

PS:现在看来,是不是少些很多代码?直接声明一个空属性,编译器就可以帮我们完成以前的私有成员字段和get、set方法,于是,我们可以通过Reflector反编译工具去看看,到底是怎么完成这个操作的。

1.3 伟大的“乡村基”—CSC(C Sharp Compiler):C#编译器

PS:这里为何会提到乡村基,一是因为乡村基的简称就是CSC,二是因为本人比较喜欢吃乡村基的中式快餐,所以,么么嗒!(感觉像是给乡村基打广告似的,不过我还是蛮喜欢乡村基的,当然是抛开价格来说)

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

  (1)首先我们来编译一下上面这个小程序,然后将编译后的exe/dll拖到反编译神器Reflector(或者ILSpy也是赞赞哒)

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

  (2)找到Person类,可以看到编译后的结果:CSC帮我们自动生成了与共有属性对应的私有字段

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

  我们可以从图中看出,自动生成的字段与以前的字段有一些区别:

  ①在每个字段上方都加上了一个[CompilerGenerated]的特性(Attribute),顾名思义:表示其是由编译器生成的;

  ②每个字段的变量名称是有一定格式的,比如<Age>k__BackingField,那么可以看出格式为:<属性名>k_BackingField;(BackingField顾名思义就是背后的字段)

  (3)看完了自动生成的字段,再来看看属性是怎么定义的:

  ①和自动生成的字段一样,属性也加上了[CompilerGenerated]的特性以示区别

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

  ②众所周知,属性就是一个get和一个set的两个方法的封装,那么我们之前写的空get/set方法又是怎么被编译生成的呢

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

  于是,我们可以看到,在get和set方法中,也加上了[CompilerGenerated]的特性以示区别,另外还帮我们自动对应了自动生成的私有字段,这就跟我们自己手动写的私有字段+共有属性的方法保持了一致。所以,自动属性是一个实用的语法糖,帮我们做了两件事:自动生成私有字段,自动在get/set方法中匹配私有字段。

二、隐式类型—关键字:var [ C# 3.0/.Net 3.x 新增特性 ]

2.1 犹抱琵琶半遮面—你能猜出我是谁?

  以前,我们在定义每个变量时都需要明确指出它是哪个类型。但是,当有了var之后,一切变得那么和谐,我们可以用一个var定义所有的类型。

    var age = ;
age += ; var name = "";
name = "edisonchou"; Console.WriteLine("age={0}", age);
Console.WriteLine("name={0}", name);

  点击调试,发现编译器自动帮我们匹配上了正确的类型并成功显示出来:

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

  那么,我们又好奇地想知道编译器到底是否识别出来了指定的类型,于是我们再次通过反编译工具来一看究竟:

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

  可以看出,我们可爱的CSC正确地帮我们推断出了正确的类型,不由得想给它点32个赞了!

  但是,变量类型不可更改,因为声明的时候已经确定类型了,例如我们在刚刚的代码中给变量赋予不同于定义时的类型,会出现错误。

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

2.2 好刀用在刀刃上—隐式类型应用场景

  在数据型业务开发中,我们会对一个数据集合进行LINQ查询,而这个LINQ查询的结果可能是ObjectQuery<>或IQueryable<>类型的对象。因此,在目标具体类型不明确的情况下,我们可以用var关键来声明:

List<UserInfo> userList = roleService.LoadRoles(param);
var data = from u in userList
where u.IsDel ==
select u;

2.3 但“爱”就是克制—隐式类型使用限制

  (1)被声明的变量是一个局部变量,而不是静态或实例字段;

  (2)变量必须在声明的同时被初始化,编译器要根据初始化值推断类型;

  (3)初始化不是一个匿名函数,同时初始化表达式也不能是 null

  (4)语句中只声明一次变量,声明后不能更改类型;(详见上面的例子)

  (5)赋值的数据类型必须是可以在编译时确定的类型

三、参数默认值和命名参数:[ C# 4.0/.NET 4.0 新增特性 ]

3.1 带默认值的方法

        static void Main(string[] args)
{
// 01.带默认值参数函数
FuncWithDefaultPara();
// 02.省略一个默认参数调用
FuncWithDefaultPara(); Console.ReadKey();
} static void FuncWithDefaultPara(int id = , bool gender = true)
{
Console.WriteLine("Id:{0},Gender:{1}", id,
gender ? "Man" : "Woman");
}

  点击调试,显示结果如下:

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

3.2 编译后的方法调用

  同样,为了一探带参数默认值方法调用的细节,我们还是借助反编译神器查看其中的玄妙:

  (1)首先,我们来看看带默认值参数的方法被编译后是怎么的:

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

  可以看到,在.NET Framework中大量采用了基于Attribute的开发方式,这里为参数添加了表示默认值的特性DefaultParameterValue

  (2)其次,再来看看Main函数中的调用过程是怎么被编译的:

  .NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

  可以看出,编译器帮我们在方法调用的括号中帮我们填充了默认值。这里,我们不禁好奇,如果在调用中,不指定ID(即使用ID默认值10010)而仅仅指定Gender为false是否可以编译通过?我们来试一下:

        static void Main(string[] args)
{
// 01.带默认值参数函数
FuncWithDefaultPara();
// 02.省略一个默认参数调用
FuncWithDefaultPara();
// 错误调用:
FuncWithDefaultPara(false); Console.ReadKey();
}

  这时,出现了以下错误:

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

  于是,我们知道,CSC也还没有那么智能,无法理解我们高深的“意图”。那么,有木有一种方法来解决这种需求呢,于是命名参数横空出世了。

3.3 使用命名参数

  在新语法中为方法调用引入了命名参数,格式为 参数名:参数值

        static void Main(string[] args)
{
// 01.带默认值参数函数
FuncWithDefaultPara();
// 02.省略一个默认参数调用
FuncWithDefaultPara();
// 错误调用:
//FuncWithDefaultPara(false);
// 03.使用命名参数调用
FuncWithDefaultPara(gender: false); Console.ReadKey();
}

  通过调试,可以得到如下结果:

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

  通过前面的分析,我们可以分析出,使用命名参数被编译之后还是会生成指定参数值的调用:

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

四、自动初始化器:[ C# 3.0/.NET 3.x 新增特性 ]

4.1 属性初始化器

  (1)在开发中,我们经常会这些为new出来的对象设置属性:

        static void InitialPropertyFunc()
{
Person p = new Person() { Name = "小强", Age = };
Console.WriteLine("Name:{0}-Age:{1}", p.Name, p.Age);
}

  (2)但是,经过编译后我们发现原来还是以前的方式:先new出来,然后一个属性一个属性地赋值。这里,编译器首先生成了一个临时对象g_initLocal0,然后为其属性赋值,最后将g_initLocal0这个对象的地址传给要使用的对象p。

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

4.2 集合初始化器

  (1)在开发中,我们经常在一个集合的实例化中,就为其初始化:

        static void InitialCollectionFunc()
{
List<Person> personList = new List<Person>()
{
new Person(){Name="小强",Age=},
new Person(){Name="小王",Age=},
new Person(){Name="小李",Age=}
}; foreach(Person person in personList)
{
Console.WriteLine("Name:{0}-Age:{1}",
person.Name, person.Age);
}
}

  (2)经过上面的集合初始化器我们了解到编译器还是会编译成原来的方式,即先new出来,为其分配了内存空间之后,再一个一个地为其属性赋值。那么,在集合的初始化中我们也可以大胆地猜测,编译器也是做了以上的优化工作:即先将每个对象new出来,然后一个一个地为属性赋值,最后调用集合的Add方法将其添加到集合中。于是,我们还是反编译一下,一探究竟:

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

附件下载

  (1)反编译神器之Reflector: http://pan.baidu.com/s/1evCJG

  (2)所谓的新语法Demo:http://pan.baidu.com/s/1ntwqdAT

作者:周旭龙

出处:http://www.cnblogs.com/edisonchou/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

.NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器的更多相关文章

  1. C&num;语法糖之第一篇&colon;自动属性&amp&semi;隐式类型

    今天给大家分享一下C#语法糖的简单的两个知识点吧. 自动属性:在 C# 4.0 和更高版本中,当属性的访问器中不需要其他逻辑时,自动实现的属性可使属性声明更加简洁. 客户端代码还可通过这些属性创建对象 ...

  2. &period;NET中那些所谓的新语法之二:匿名类、匿名方法与扩展方法

    开篇:在上一篇中,我们了解了自动属性.隐式类型.自动初始化器等所谓的新语法,这一篇我们继续征程,看看匿名类.匿名方法以及常用的扩展方法.虽然,都是很常见的东西,但是未必我们都明白其中蕴含的奥妙.所以, ...

  3. &period;NET中那些所谓的新语法之三:系统预定义委托与Lambda表达式

    开篇:在上一篇中,我们了解了匿名类.匿名方法与扩展方法等所谓的新语法,这一篇我们继续征程,看看系统预定义委托(Action/Func/Predicate)和超爱的Lambda表达式.为了方便码农们,. ...

  4. &period;NET中那些所谓的新语法之四:标准查询运算符与LINQ

    开篇:在上一篇中,我们了解了预定义委托与Lambda表达式等所谓的新语法,这一篇我们继续征程,看看标准查询运算符和LINQ.标准查询运算符是定义在System.Linq.Enumerable类中的50 ...

  5. C&num;中的隐式类型var——详细示例解析

    从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,它的具体类型由编译器根据上下文推断而出. 下面就让我来总结下隐式类型的一些特点: 1.va ...

  6. &period;NET中那些所谓的新语法

    .NET中那些所谓的新语法之四:标准查询运算符与LINQ 摘要: 开篇:在上一篇中,我们了解了预定义委托与Lambda表达式等所谓的新语法,这一篇我们继续征程,看看标准查询运算符和LINQ.标准查询运 ...

  7. c&num;4&period;5新语法--自动属性和隐式类型

    1.自动属性    自动属性是c#中属性定义的两种形式的一种:传统属性定义.自动属性.    1.1 传统属性定义        private int _age;        public int ...

  8. C&num;3&period;0新特性&colon;隐式类型、扩展方法、自动实现属性,对象&sol;集合初始值设定、匿名类型、Lambda,Linq,表达式树、可选参数与命名参数

    一.隐式类型var 从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,编译器自动推断类型. 1.var类型的局部变量必须赋予初始值,包括匿名 ...

  9. javascript中的隐式类型转化

    javascript中的隐式类型转化 #隐式转换 ## "+" 字符串和数字 如果某个操作数是字符串或者能够通过以下步骤转换为字符串的话,+将进行拼接操作. 如果其中一个操作数是对 ...

随机推荐

  1. ASP&period;NET Core 中文文档 第四章 MVC(3&period;2)Razor 语法参考

    原文:Razor Syntax Reference 作者:Taylor Mullen.Rick Anderson 翻译:刘怡(AlexLEWIS) 校对:何镇汐 什么是 Razor? Razor 是一 ...

  2. IOS开发基础知识--碎片33

    1:AFNetworking状态栏网络请求效果 直接在AppDelegate里面didFinishLaunchingWithOptions进行设置 [[AFNetworkActivityIndicat ...

  3. 第16&sol;24周 SQL Server 2014中的基数计算

    大家好,欢迎回到性能调优培训.上个星期我们讨论在SQL Server里基数计算过程里的一些问题.今天我们继续详细谈下,SQL Server 2014里引入的新基数计算. 新基数计算 SQL Serve ...

  4. 【英语】Bingo口语笔记&lpar;68&rpar; - come系列

  5. GlusterFS创建volume失败的解决方法(&ast; or a prefix of it is already part of a volume)

    问题描写叙述: 之前已经创建了一个replicated的volume gv0,replica=2,两个文件夹为:/test/data1和/test/data2,之后发现这两个文件夹不太合适,想在/te ...

  6. sencha touch2 动画问题

    最近在review一个项目的代码, 发现返回操作比较乱,很多"从哪里来,到哪里去的操作"被写的一塌糊涂; 按照ios系统的进场出场动画(人家的体验还是很好的,必须借鉴)为标准,使用 ...

  7. 用了 CSDN 的 markdown 编辑器吐槽下~~

    吐槽一下.. . 第一次用 CSDN 的这个 markdown 编辑器,首先感官上看起来还是非常大气相比曾经那个 HTML 编辑器实在时上了N个档次,但实际使用的体验实在是比較糟糕的.希望能改进下哦: ...

  8. Qt终结者之粒子系统

    前言 粒子系统用于模拟一些特定的模糊效果,如爆炸.烟火.雪花.水流等.使用传统的渲染技术实现粒子效果比较困难,但是使用QML粒子系统能十分方便的实现各种粒子效果,使你的界面更加炫酷,动感. QML中的 ...

  9. SQL Server 将一个表中字段的值复制到另一个表的字段中

    具体方法如下 一:update 表2 set (要插入的列名)= select 表1.某一列 from 表1 left jion 表2 on 表1和表2的关联 where ..... 二:update ...

  10. c&num;&colon; TabControl隐藏选项卡&lpar;WizardPages&rpar;

    如Delphi之TPageControl控件,其TTabSheet有TabVisible属性,在制作类似Wizard页面切换时,甚为有用. 而c#对应之TabControl控件,其页面TabPage无 ...