第1章 C#和.NET Framework简介
第1章 C#和.NET Framework简介
1.6 CLR 和 .NET Framework
.NET Framework 由 CLR 和大量程序库组成。这些程序库由核心库和应用库组成,应用库依赖于核心库。下图是这些程序库的可视化概况:
1.8 C# 简史
思维导图
1.8.1 C#7.0 新特性
(C#7.0 随 Visual Studio 2017 发布。)
1.8.1.1 数字字面量的改进
C#7 中,数字字面量可以使用下划线来改善可读性,它们称为数字分隔符而被编译器忽略:
int million = 1_000_000;
二进制字面量可以使用 0b 前缀进行标识:
var b = 0b1010_1011_1100_1110_1111;
1.8.1.2 输出变量及参数忽略
C#7 中,调用含有 out 参数的方法将更加容易。首先,可以非常自然地声明输出变量:
bool successful = int.TryParse("123", out int result);
Console.WriteLine(result);
当调用含有多个 out 参数的方法时,可以使用下划线字符忽略你不关心的参数:
SomeBigMethod(out _, out _, out _, out int x, out _, out _, out _);
Console.WriteLine(x);
1.8.1.3 模式
is 运算符可以自然地引入变量,称为模式变量:
void Foo(object x){
if(x is string s)
Console.WriteLine(s.Length);
}
switch 语句同样支持模式,此时 case 子句对应的是类型而非常量;可以使用 when 子句来指定一个判断条件;或是直接选择 null:
object x = null;
switch (x)
{
case int i:
Console.WriteLine("It's an int!");
break;
case string s:
Console.WriteLine(s.Length);
break;
case bool b when b == true:
Console.WriteLine("True");
break;
case null:
Console.WriteLine("Nothing");
break;
}
1.8.1.4 局部方法
局部方法是声明在其他函数内部的方法
void WriteCubes()
{
Console.WriteLine(Cube(3));
Console.WriteLine(Cube(4));
Console.WriteLine(Cube(5));
int Cube(int value) => value * value * value;
}
局部方法仅仅在其包含函数内可见,它们可以像 Lambda 表达式那样捕获局部变量。
1.8.1.5 更多的表达式体成员
C#6 引人了以“胖箭头”语法表示的表达式体的方法、只读属性、运算符以及索引器。而 C#7 更将其扩展到了构造函数、读/写属性和终结器中:
public class Person
{
string name;
public Person (string name) => Name name;
public string Name
{
get => name;j
set => name = value ?? "";
}
~Person() => Console.WriteLine ("finalize");
}
1.8.1.6 解构器
解构方法允许你将一个对象的属性或字段“解构”到一组变量中。这通常是通过在类型中定义一个名为 Deconstruct
的方法来实现,该方法以 out 参数的形式输出多个值。
从 C#7.0 开始,这个特性被引入,允许开发者轻松地从对象中提取数据。这在元组的使用中特别有用,因为你可以在一个单独的语句中从对象中提取多个字段或属性:
var joe = new Person("Joe Bloggs");
// 使用解构方法将Person对象的属性解构到两个变量中
var (first, last) = joe;
Console.WriteLine(first); // Joe
Console.WriteLine(last); //Bloggs
public class Person
{
public string name;
public Person(string name){
this.name = name;
}
// 解构方法
public void Deconstruct(out string firstName, out string lastName)
{
int spacePos = name.IndexOf(' ');
firstName = name.Substring(0, spacePos);
lastName = name.Substring(spacePos + 1);
}
}
1.8.1.7 元组
C#7 允许显式定义元组,新元组实质是 System.ValueTuple<...>
泛型结构的语法糖:
var bb = ("Bob", 23);
Console.WriteLine(bob.Item1);
Console.WriteLine(bob.Item2);
元组可以做到:
- 对元素进行命名
- 使用元组做返回值,而非out参数
- 隐式支持解构模式
元素进行命名:
var tuple = (Name:"Bob", Age:23);
Console.WriteLine(tuple.Name);
Console.WriteLine(tuple.Age);
使用元组做返回值,而非out参数:
var pos = GetFilePosition();
Console.WriteLine(pos.row);
Console.WriteLine(pos.column);
static (int row, int column) GetFilePosition() => (3, 10);
隐式支持解构模式:
元组隐式地支持解构模式,因此很容易解构为若干独立的变量,上述代码可以改成:
var (row, column) = GetFilePosition();
Console.WriteLine(row);
Console.WriteLine(column);
(int row2, int column2) = GetFilePosition();
Console.WriteLine(row2);
Console.WriteLine(column2);
1.8.1.8 throw 表达式
在 C#7 之前,throw 一直是一个语句(Statement)。现在它也可以作为表达式(Expression)出现在表达式体函数中:
public string Foo() => throw new NotImplementedException();
throw 表达式也可以出现在三目运算符中:
string Capitalize(string value) =>
value == null ? throw new ArgumentException("value") :
value == "" ? "" :
char.ToUpper(value[0]) + value.Substring(1);
1.8.2 C#6.0 新特性
(C#6.0 随Visual Studio 2015发布)
1.8.2.1 null 条件运算符(Elvis)
null 条件运算符(参见2.10 null 运算符)可以避免在调用方法或访问类型的成员之前显式地编写用于 null 判断的语句。在以下示例中,result 将会为 null 而不会抛NullReferenceException
:
StringBuilder sb = null
string result = sb?.ToString();
1.8.2.2 表达式体函数(expression-bodied function)
参见3.1.2.1 表达式体方法(C#6),可以以Lambda表达式的形式书写仅仅包含一个表达式的方法、属性、运算符以及索引器,使代码更加简短:
public int TimesTwo(int) => x * 2;
public string SomeProperty => "Property value";
1.8.2.3 属性初始化器(property initializer)
参见3.1.4 对象初始化器,可以对自动属性进行初始赋值:
public DateTime TimeCreated { get; set; } = DateTime.Now;
这种初始化也支持只读属性:
public DateTime TimeCreated { get; } = DateTime.Now;
1.8.2.4 索引初始化器(index initializer)
参见4.6.2 集合的初始化器,可以一次性初始化具有索引器的任意类型:
var dict = new Dictionary<int, string>()
{
[3] = "three",
[10] = "ten"
};
1.8.2.5 字符串插值(string interploation)
参见2.6.2.2 字符串插值(C#6),简化了string.Format
:
string s = $"It is {DateTime.Now.DayOfWeek} today";
1.8.2.6 异常过滤器(exception filters)
参见异常筛选器(C#6),可以在catch块上再添加一个条件:
string html;
try
{
html = new WebClient().DownloadString("http://asef");
}
catch(WebException ex) when(ex.Status == WebExceptionStatus.Timeout)
{
...
}
1.8.2.7 using static
参见2.12.2 using static 指令(C#6),可以引入一个类型的所有静态成员,这样就可以不用书写类型而直接使用这些成员:
using static System.Console;
...
WriteLine("Hello, world");
1.8.2.8 nameof
参见3.1.13 nameof 运算符(C#6),nameof
运算符返回变量、类型或其他符号的名称,这样在vs中可以避免重命名造成不一致的代码:
int capacity = 123;
string x = nameof(capacity); // x是"capacity"
string y = nameof(Uri.Host); // y是"Host"
1.8.3 C#5.0 新特性
C#5.0最大的新特性是通过两个关键字,async和await,支持异步功能(asynchronous function)。异步功能支持异步延续(asynchronous continuation),从而简化响应式和线程安全的富客户端应用程序的编写。它还有利于编写高并发和高效的I/O密集型应用程序,而不需要为每一个操作绑定一个线程资源。
1.8.4 C#4.0 新特性
C#4.0 增加的新特性有:
- 动态绑定
- 可选参数和命名参数
- 用泛型接口和委托实现类型变化
- 改进COM互操作性
1.8.5 C#3.0 新特性
- LINQ(Language Integrated Query)
- 隐式类型局部变量(var)
- 匿名类型(用于LINQ查询结果的输出)
- 对象初始化器
- Lambda表达式
- 扩展方法
- 查询表达式
- 表达式树
上述内容都是为LINQ服务的,除此还添加了:
- 自动化属性
- 分部方法(Partial Method)
1.8.6 C#2.0 新特性
-
泛型
泛型需要在运行时仍能确保类型的正确性,因此引入了CLR2.0
-
可空类型(nullable type)
-
迭代器
-
匿名方法(Lambda表达式的前身)
上述方法为 C#3 的LINQ铺平了道路。此外,还有:
- 分布类
- 静态类
- 命名空间别名
- 友元程序集
- 支持定长缓冲区
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤