目录

一、C#语法糖大汇总

1. 经过简化的Property
2. 经过两次变异的委托写法
3. 集合类的声明
4. 集合类各个项的操作
5. using == try finally
6. 可爱的var
7. 问号的演变
8. 类型实例化的语法糖
9. 传说中的扩展方法
10.使用匿名类

二、C#之6.0语法糖剖析

2.1 自动属性默认初始化
2.2 自动只读属性默认初始化
2.3 表达式为主体的函数
2.4 表达式为主体的属性(赋值)
2.5 静态类导入
2.6 Null条件运算符
2.7 字符串格式化
2.8 索引初始化
2.9 异常过滤器when
2.10 catch和finally代码块内的Await
2.11 nameof表达式
2.12 扩展方法
总结


一、C#语法糖大汇总

首先需要声明的是“语法糖”这个词绝非贬义词,它可以给我带来方便,是一种便捷的写法,编译器会帮我们做转换;而且可以提高开发编码的效率,在性能上也不会带来损失。这让java开发人员羡慕不已,呵呵。

1.  经过简化的Property

早些时候我们这样声明Property

private string _myName;
public string MyName
{
get { return _myName; }
set { _myName = value; }
}

千篇一律的这样声明,没有多大意义,于是C#的设计人员将这个千篇一律的工作交给了编译器帮我们做了,我们现在可以这样声明

public string MyName { get; set; }

当然他不会牺牲灵活性,我们可以单独给get或者set设定访问限制符,例如

public string MyName { get; protected internal set; }

2.  经过两次变异的委托写法

在.net 1.1时我们不得不声明方法后才在委托中使用,在.net 2.0之后我们可以使用匿名委托,他不单可以简化写法,还可以在匿名委托中访问范围内的变量;再后来拉姆达表达式来了,写法就更简便了。

class MyClass
{
public delegate void DoSomething(int a);
//定义方法委托
private void DoIt(int a) {
Console.WriteLine(a);
}
private void HowtoDo(DoSomething doMethod,int a) {
doMethod(a);
}
public static void Main(string[] args) {
MyClass mc = new MyClass();
//调用定义的方法委托
mc.HowtoDo(new DoSomething(mc.DoIt), );
int x = ;
//使用匿名委托
mc.HowtoDo(delegate(int a){
Console.WriteLine(a + x);
},);
//使用lamda表达式
mc.HowtoDo(a=>Console.WriteLine(a+x),);
Console.ReadLine();
}
}

3.  集合类的声明

//之前我们声明一个List并给list赋初始值,必须得这么写:
List<string> list = new List<string>();
list.Add("a一");
list.Add("b二");
list.Add("c三"); //现在不需要了,直接写就可以了
List<string> list = new List<string> {"def","OK"};

4.  集合类各个项的操作

//我们为了逐个处理集合中的项,需要这么写:
foreach (string item in list)
{
Console.WriteLine(item);
} //现在不需要了,这样就可以了
list.ForEach(a => Console.WriteLine(a));

5.  using == try finally

为了在使用完毕时释放资源,我们经常要用using,using实质上就是try fiannaly的一个语法糖而已。例如

StreamWriter sw = null;
try
{
sw = new StreamWriter("d:\abc.txt");
sw.WriteLine("test");
}
finally {
if(sw!= null) sw.Dispose();
} //上面的代码可以简化为:
using (var sw = new StreamWriter("d:\abc.txt")) {
sw.WriteLine("test");
}

6.  可爱的var

var的意义时不必写声明的类型,编译器会根据后面对var的赋值判断它的类型,var的类型一旦确认就不能再改变,它只能作为局部变量使用,不能用做字段也不能用做参数声明。

var writer = new StreamWriter(path);

for(var i=;i<;i++){}

7.  问号的演变

老掉牙的一个问号+冒号

var b = ;
var a = b > ?b.ToString():””+b;

新宝宝两个问号 ??,它表示左边的变量如果为null则值为右边的变量,否则就是左边的变量值

string a = null;
var b = a??””;

8.  类型实例化的语法糖

public class Abc
{
public int ID { get; set; }
public string Name { get; set; }
public string Url { get; set; }
} //我们没有为上面的类声明构造函数,但是我们可以像下面的形式来实例化它
public static void Main(string[] args) {
var abc = new Abc{
ID=,
Name="yukaizhao",
Url="http://yukaizhao.cnblogs.com/"
};
}

9.  传说中的扩展方法

在c#3.5时引入了扩展方法,我们可以在不修改类源码的情况下给类增加实例方法,这个很有意义。它的实质也是一种语法糖的实现
例如我们给String类扩展一个IsNumber的方法:

public static class StringExt {
static private Regex regexNumber = new Regex("\\d+");
static public bool IsNumber(this string input)
{
if (string.IsNullOrEmpty(input))
{
return false;
}
return regexNumber.IsMatch(input);
}
} //我们可以在String实例上调用这个方法了
var abc = “”;
var isNumber = abs.IsNumber();

10.使用匿名类

var a = new {
ID = ,Name=”yukaizhao”,BlogUrl=”http://www.cnblogs.com/yukaizhao/”
};

匿名类在linq to sql或者entity framework中返回查询数据时很好用。


C#6

静态类导入using static System.Console;

11. NULL条件运算符

//使用代码
Customer customer = new Customer();
string name = customer?.Name; //编译代码
Customer customer = new Customer();
if (customer != null)
{
string name = customer.Name;
}

也可以和??组合起来使用

if (customer?.Face()??false)

还可以两个一起组合来使用

int? contactNameLen = contact?.Name?.Length; 

这个语法糖的目的是在对象使用前检查是否为null。如果对象为空,则赋值给变量为空值,所以例子中需要一个可以为空的int类型、即int?。如果对象不为空,则调用对象的成员取值,并赋值给变量。

12. 字符串格式化

String.Format有些不方便的地方是:必须输入"String.Format",使用{0}占位符、必须顺序来格式化、这点容易出错。

var contactInfo = string.Format("Id:{0} Name:{1} EmailAddr:{2} PhoneNum:{3}", contact.Id, contact.Name, contact.EmailAddress, contact.PhoneNum);

//新的语法
var contactInfo2 = $"Id:{contact.Id} Name:{contact.Name} EmailAddr:{contact.EmailAddress} PhoneNum:{contact.PhoneNum}"; //新格式化方式还支持任何表达式的直接赋值:
var contactInfo = $"Id:{contact.Id} Name:{(contact.Name.Length == 0 ? "Frank" : contact.Name)} EmailAddr:{contact.EmailAddress} PhoneNum:{contact.PhoneNum}";

二、C#之6.0语法糖剖析

2.1 自动属性默认初始化

//使用方法:
public string Name { get; set; } = "hello world"; //为了便于理解使用2.0语法展示,编译器生成代码如下:
public class Customer
{
[CompilerGenerated]
private string kBackingField = "hello world";
public Customer()
{
  this.kBackingField = "hello world";
} public string Name
{
[CompilerGenerated]
get
{
return this.<Name>k__BackingField;
}
[CompilerGenerated]
set
{
this.<Name>k__BackingField = value;
}
}
}
//从生成代码中可以看出编译器是在实例构造函数时,初始化属性信息的。

2.2 自动只读属性默认初始化

//使用方法:
public string Name1 { get; } = "hello world"; //编译器生成代码如下:
[CompilerGenerated]
private readonly string kBackingField;
public Customer()
{
this.kBackingField = "hello world";
}
public string Name1
{
[CompilerGenerated]
get { return this.k__BackingField; }
}
//由于初始化默认值实在构造函数中赋值的,所以跟属性只读没关系。

2.3 表达式为主体的函数

//使用方法:
Body Get(int x, int y) => new Body( + x, + y); //编译器生成如下:
private Program.Body Get(int x, int y)
{
return new Program.Body( + x, + y);
}
//简化了单行方法的编写,省去写大括号的功夫。 //同时支持没有返回值的写法:
void OutPut(int x, int y) => Console.WriteLine("hello world"); //也支持异步函数的编写:
async void OutPut(int x, int y) => await new Task(() => Console.WriteLine("hello wolrd"));

2.4 表达式为主体的属性(赋值)

//使用方法:
public string Name2 => "hello world"; //编译器生成代码如下:
public string Name2
{
  get { return "mushroomsir"; }
}
//编译器只生成了个只读属性。

2.5 静态类导入

//这个特性可以一次性导入某类型的所有静态成员,使静态成员在后面的代码中没有类型限制直接使用,像使用本类型下面的静态方法一样。
using static System.Console;
class Program
{
  static void Main(string[] args)
  {
    WriteLine("hello wolrd");
  }
} //编译器生成代码如下:
private static void Main(string[] args)
{
  Console.WriteLine("hello wolrd");
}
//省去了类型名称的重复编写。

2.6 Null条件运算符

//使用方法:
Customer customer = new Customer();
string name3 = customer?.Name; //等同于:
Customer customer = new Customer();
if (customer1 != null)
{
string name = customer1.Name;
} //可以和??组合起来使用:
if (customer?.Face2()??false) //还可以2个一起用:
int? Length = customer?.Name?.Length; //也可以方法调用:
customer?.Face();

这个语法糖的目的是在对象使用前检查是否为null。如果对象为空,则赋值给变量为空值,所以例子中需要一个可以为空的int类型、即int?。

如果对象不为空,则调用对象的成员取值,并赋值给变量。

2.7 字符串格式化

//String.Format有些不方便的地方是:必须输入"String.Format",使用{0}占位符、必须顺序来格式化、这点容易出错。
var s = String.Format("{0} is {1} year {{s}} old", p.Name, p.Age); //新的语法糖使用起来相对更轻松些:
var s = $"{p.Name} is {p.Age} year{{s}} old"; //编译器生成如下,和之前没有区别:
var s = String.Format("{0} is {1} year{{s}} old", p.Name, p.Age); //有趣的是,新格式化方式还支持任何表达式的直接赋值:
var s = $"{p.Name} is {p.Age} year{(p.Age == 1 ? "" : "s")} old";

2.8 索引初始化

//List虽然这样写可以编译通过,但是会抛异常的,使用方法:
var numbers = new List<string> { [] = "seven", [] = "nine", [] = "thirteen" }; //编译器生成代码如下:
List list = new List();
list[] = "seven";
list[] = "nine";
list[] = "thirteen";

//Dictionary可以执行,因为二者内部索引机制不一样:
var numbers = new Dictionary<int, string> {[] = "seven",[] = "nine",[] = "thirteen" }; //编译器生成代码:
Dictionary<int, string> dictionary2 = new Dictionary<int, string>();
dictionary2[] = "seven";
dictionary2[] = "nine";
dictionary2[] = "thirteen";
Dictionary<int, string> dictionary = dictionary2;

2.9 异常过滤器when

//使用方法:
try
{
throw new ArgumentException("string error");
}
catch (ArgumentException e) when (myfilter(e))
{
Console.WriteLine(e.Message);
} static bool myfilter(ArgumentException e)
{
return false;
}

When语法作用是:在进入到catch之前、验证when括号里myfilter方法返回的bool,如果返回true继续运行,false不走catch直接抛出异常。

使用这个filter可以更好的判断一个错误是继续处理还是重新抛出去。按照以前的做法,在catch块内如需再次抛出去,需要重新throw出去,这时的错误源是捕捉后在抛的,而不是原先的,有了when语法就可以直接定位到错误源。

2.10 catch和finally代码块内的Await

Await异步处理是在c#5.0提出的,但不能在catch和finally代码块内使用,这次在C#6.0更新上支持了。

使用方法:

   async void Solve()
{
try
{
await HttpMethodAsync();
}
catch (ArgumentException e)
{
await HttpMethodAsync();
}
finally
{
await HttpMethodAsync();
}
}

编译器把catch和finally的await生成到状态机里面的MoveNext()里面。原来里面只有 TaskAwaiter,现在多了2个。状态机里面的代码和原先的一样,只是更复杂了下,有兴趣的童鞋可以先看下Async、Await剖析再去深究。

2.11 nameof表达式

//使用方法:
string name = "";
Console.WriteLine(nameof(name));
//控制台输出 "name"。

有时候会需要程序中一些成员的字符串名称,比如抛出ArgumentNullException异常的时候,想知道ArgumentNullException类型的字符串名称,这时候就可以用nameof获取字符

串“ArgumentNullException”。现在做法都是手动复制一下,但重构改名的时候容易忘记变更字符串,使用nameof就可以避免了。

//当如下使用的时候,编译器会只取最后的ZipCode。
nameof(person.Address.ZipCode) //编译器生成如下代码:
Console.WriteLine("name");

2.12 扩展方法

    using static System.Linq.Enumerable; //引入类型,而不是命名空间
class Program
{
static void Main()
{
var range = Range(, ); // Ok: 不是扩展方法
var odd = Where(range, i => i % == ); // Error, 不在全局作用域里
var even = range.Where(i => i % == ); // Ok
}
}

首先Enumerable是个静态类,里面是各种扩展方法,比如range。static的作用是把类型的静态成员一次性导入,rang虽然是静态方法,但不能导入,比如where。

因为扩展方法虽然是一个静态方法,但是语法规定它作为一个实例方法使用(打点),所以不能在全局作用域里当静态方法用,因此var odd = Where(range, i => i % 2 == 1)是错误的。

但是static却能把类型的扩展方法作为扩展方法本身角色的功能导入进去,所以var even = range.Where(i => i % 2 == 0)是ok的。

这里可能稍微有点绕,lz尽量写清楚,static新用法有2个功能:

把静态成员导入,但扩展方法比较特殊、排除在外。这时static是c# 6.0的新功能。
等同于把扩展方法的命名空间导入,所以在集合上可以打点调用扩展方法。这是之前就有的功能,而不是把扩展方法转成单纯的静态方法导入使用。

总结

看到园子里有介绍的文章,一时来兴趣了,下班后安装个社区版就研究分享下。 虽然微软一直出新东西,但都是由下至上迭代的,所以学习起来是非常快的。

C#语法糖(Csharp Syntactic sugar)的更多相关文章

  1. C#常用語法糖(Csharp Syntactic sugar)

    首先需要声明的是“语法糖”这个词绝非贬义词,它可以给我带来方便,是一种便捷的写法,编译器会帮我们做转换:而且可以提高开发编码的效率,在性能上也不会带来损失.这让java开发人员羡慕不已,呵呵. 1.  ...

  2. Csharp Syntactic sugar

    C#语法糖(Csharp Syntactic sugar)大汇总 首先需要声明的是“语法糖”这个词绝非贬义词,它可以给我带来方便,是一种便捷的写法,编译器会帮我们做转换:而且可以提高开发编码的效率,在 ...

  3. C#语法糖(Csharp Syntactic sugar)大汇总

    首先需要声明的是"语法糖"这个词绝非贬义词,它可以给我带来方便,是一种便捷的写法,编译器会帮我们做转换:而且可以提高开发编码的效率,在性能上也不会带来损失.这让java开发人员羡慕 ...

  4. C#语法糖,让编程更具乐趣

    一.什么是语法糖 语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法 ...

  5. Java中的10颗语法糖

    语法糖(Syntactic Sugar):也称糖衣语法,指在计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用.通常来说,使用语法糖能够增加程序的可读性,减少程序代码出错的 ...

  6. 语法糖----JAVA

    语法糖 语法糖(Syntactic Sugar),也叫糖衣语法,是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语.指的是,在计算机语言中添加某种语法,这种语法能使程序 ...

  7. 转:【深入Java虚拟机】之六:Java语法糖

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/18011009 语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家P ...

  8. Java 中的语法糖

    百度百科对语法糖的定义 语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这 ...

  9. Java 语法糖详解

    语法糖 语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家 Peter.J.Landin 发明的一个术语,指在计算机语言中添加的某种语法. 这种语法对语言的功能并没有影响,但是 ...

随机推荐

  1. How to enable flash on Chromium

    sudo apt install chromium-browser pepperflashplugin-nonfree

  2. LNMP平台部署

    LNAP平台概述 百度百科 LNMP代表的就是:Linux系统下Nginx+MySQL+PHP这种网站服务器架构. Linux是一类Unix计算机操作系统的统称,是目前最流行的免费操作系统.代表版本有 ...

  3. BZOJ4205卡牌配对——最大流+建图优化

    题目描述 现在有一种卡牌游戏,每张卡牌上有三个属性值:A,B,C.把卡牌分为X,Y两类,分别有n1,n2张. 两张卡牌能够配对,当且仅当,存在至多一项属性值使得两张卡牌该项属性值互质,且两张卡牌类别不 ...

  4. D. Flood Fill 区间DP 或lcs匹配

    题意 给定一串数字 相同的连续的数字可以同时 转换成一个相同数字 问最小几次可以全部转换成一个相同的数字 法1:区间dp  dp[l][r][0/1]  0表示l r区间转化成和最左边相同需要多少次 ...

  5. Tmutarakan Exams URAL - 1091(莫比乌斯函数 || 容斥)

    题意: 求1 - s 中 找出k个数 使它们的gcd  > 1 求这样的k个数的对数 解析: 从每个素数的倍数中取k个数  求方案数 然后素数组合,容斥一下重的 奇加偶减 莫比乌斯函数的直接套模 ...

  6. bzoj 1029: [JSOI2007]建筑抢修 (优先队列)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1029 思路: 按结束时间排序,优先选结束时间短的,选完后扔到优先队列里(大的优先),如果选到 ...

  7. Educational Codeforces Round 58 A,B,C,D,E,G

    A. Minimum Integer 链接:http://codeforces.com/contest/1101/problem/A 代码: #include<bits/stdc++.h> ...

  8. 安装 xadmin 报错: Command "python setup.py egg_info" failed with error code 1 in C:\Users\Python\AppData\Local\Temp\pip-install-1k1byg0p\xadmin\

    报错详情 安装 xadmin 组件的时候报错 不论是命令行还是 pycharm 方式都不行 分析报错 按照报错提示是说 README.rst 文件的编码问题导致. 解决报错 通过 github 下载源 ...

  9. 常用 git 基础命令

    git config --global credential.helper store记住密码 git config user.name xxx配置帐号 git config user.email x ...

  10. git同步远程已删除的分支和删除本地多余的分支

    使用 git branch -a 可以查看本地分支和远程分支情况 但远程分支(红色部分)删除后,发现本地并没有同步过来. 一. 同步本地的远程分支 查看本地分支和追踪情况: git remote sh ...