C# 一门与时俱进的语言
类型系统
- 类型系统:C#是一门静态类型语言;需要在代码中明确给出变量、参数以及返回值的类型等
- C# 2 引入了可空值类型(nullable value type)。利用它可以有效表示未定的变量值,从而摆脱魔数(把-1用作集合的索引,或者用DateTime.MinValue表示日期等)的使用。
- C# 7,使用者还可以采用readonly struct 这样的声明,将自定义结构体声明为不可变类型。此项特性原本旨在提升编译器生成代码的效率,但是也助于开发人员更准确的表达代码意图。
- C# 8还计划加入可空引用类型(nullable refe
rence type)。C# 8假设任何没有显示声明为可空的值都为非可空值,例如下面这个方法声明
string Method(string x,string ? y)
该方法参数与的类型很明确:x是非可空值,y则是可空值。方法的返回值(没有?符号)表示函数的返回值也是非可空的。 - C# 3引入了匿名类型(anonymous type)和隐式局部变量(var),二者用于解决某些静态类型语言的缺陷:代码冗余。对于一个仅在单一方法中使用的数据形态,如果要为其专门创建额外的数据类型,不善于牛刀杀鸡。而使用匿名类型的好处在于,保持静态类型语言优势的同时,可以清晰简洁的描述数据形态。
var book = new {Title=""Lost in the snow,Author = "Holly Webb"};
string title = book.Title;
string author = book.Author;
匿名类型主要用于LINQ查询语句,不过即便没有LINQ,为单一方法专门创建数据类型这种做法也不太可取。同样,如果调用了某类型的构造方法,就没有必要在同一条语句中显示声明该变量的类型了。下面两种声明方式哪一个更简洁一目了然:
Dictionary<string,string> map1 = new Dictionary<string,string>();//显示类型
var map2 = new Dictionary<string,string>();//隐式类型
隐式类型在处理匿名类型时不可或缺,在处理普通类型时,其重要性日益凸显。需要重点区分隐式类型和动态类型这两个概念。注意以上代码中的变量map2,它属于静态类型,只是没有显示写出其类型而已。
- 不过,匿名类型的作用域仅限于单个代码块,无法作用于方法的参数或者返回值。C# 7 引入元组的概念。元组是一种值类型变量,它可以有效的组织变量。元组的framework支持相对比较简单,单还需要额外的语言支持来实现对元素进行命名。可以使用元组来替代前文中的匿名类型:
var book = { title = "Lost in the Snow",author = "Holly webb"};
Console.WriteLine(book.title);
用元组替代匿名类型的用法只适用于部分场合,其好处之一是元组可以用作方法的参数和返回值。
代码更简洁
1.构造与初始化
首先考虑对象构造和初始化的方式。**委托(delegate)**应该是演化最多而且最快的一项特性。在C# 1 中,需要先写一个委托可以指向的方法,然后再写一大段代码来创建委托。例如,为一个按钮的Click事件订阅一个新的事件处理方法,在C# 1代码如下所示:
button.Click += new EventHandler(HandleButtonClick);
C# 2引入方法组转换和匿名方法后,就可以采用以下方式来保存HandleButtonClick方法了:
button.Click += HandleButtonClick;//C#2
如果Click处理方法比较简单,也可以写一个匿名方法,不需要再单独创建方法:
button.Click += delegate{ MessageBox.Show("Clicked!"); };//C#3
另外,匿名函数的闭包(closure) 特性还有额外的好处:在匿名函数中访问其所在的上下文的局部变量。不过自从C# 3退出lambda表达式之后,匿名函数已渐渐失宠,因为lambda表达式几乎具备了匿名函数所有的特长,而且它的语法更简洁。
button.Click += (sender,args) => MessageBox.Show("Clicked"); //C#3
2.方法与属性声明
- 自动实现的属性 是C#代码简洁中最显著的特性之一。例如C#1实现的以下代码:
private string name;
public string Name{
get { return name ;}
set { name = value; }
}
如果采用自动实现的属性,则仅需一行代码:
public string Name { get; set; }
此外,C# 6引入的表达式主题成员 进一步降低了C#语言的复杂度。假设有一个封装了string集合的类,该集合的Count和GetEnumerator()这两个成员,在C# 6以前需要写成如下形式:
public int Count { get { retrn list.Count;} }
public IEnumerator<string> GetEnumerator(){
return list.GetEnumerator();
}
有了C# 6,就可以使用=>标记作为表达式主体成员,大幅简化代码:
public int Count => list.Count;
public IEnumerator<string> GetEnumertor()=>list.GetEnumerator();
- C# 6 引入了内插字符串字面量 如以下代码:
throw new KeyNotFoundException($"No calendar system for ID {id} exists")
3.异步
C#5 采用async/await机制,进一步简化了主流语言的异步编程模式。此项特性共包含2项关于async方法的补充内容。
- async方法会生成一个返回值,该返回值代表一个异步操作。这部分完全不需要开发人员介入。该返回值的类型一般是Task或者Task<T>。
- async方法使用await表达式来消费异步操作。如果async方法使徒等待一个尚未完成的操作,该方法就会异步地暂停,直到操作完成后再继续进行。
借上述特性,我们可以按照编写同步代码的方式来编写异步代码,同时让并发操作更接近自然的思维方式。参考如下示例代码,假设有一个由WindowsForms事件触发的异步方法:
private async Task UpdateStatus(){
Task<Weather> weatherTask = GetWeatherAsync(); //同时开始
Task<EmailStatus> emailTask = GetEmailStatusAsync();//两个操作
Weather weather = await weatherTask; //异步地等待
EmailStatus email = await emailTask; //二者完成
weatherLabel.Text = weather.Desc; //更新用户界面
inboxLabel.Text = email.InboxCount.ToString();
}
未完待续。。。。。