在开始深入探讨.NET Core之前,首先需要明确讨论的组件:.NET运行时(CLR)、基础类库(BCL)以及C#语言(包括VB.NET)都是独立版本化的,但通常与.NET Framework一起发布,并且常常伴随着新的Visual Studio版本。
.NET Framework是一个由微软开发的应用程序开发平台,它允许开发者创建Windows应用程序。它包括.NET运行时(CLR)和基础类库(BCL),以及多种编程语言,如C#和VB.NET。
Visual Studio是一个由微软开发的集成开发环境(IDE),它支持多种编程语言,包括C#、VB.NET和C++。Visual Studio与.NET Framework紧密集成,提供了丰富的工具和功能,帮助开发者构建、测试和部署.NET应用程序。
版本 | 发布年份 | .NET运行时 | 基础类库 | C#语言 | 重大新特性 |
---|---|---|---|---|---|
1.0 | 2002 | 1.0 | 1.0 | 1.0 | - |
1.1 | 2003 | 1.1 | 1.1 | 1.2 | - |
2.0 | 2005 | 2.0 | 2.0 | 2.0 | 泛型 |
3.0 | - | 2.0 | 3.0 | 2.0 | WPF |
3.5 | 2008 | 2.0 | 3.5 | 3.0 | LINQ |
4.0 | 2010 | 4.0 | 4.0 | 4.0 | dynamic关键字、可选参数 |
4.5 | 2012 | 4.0 | 4.5 | 5.0 | async关键字 |
4.5.1 | 2013 | 4.0 | 4.5.1 | 5.0 | - |
4.6 | 2015 | 4.0 | 4.6 | 6.0 | 空条件运算符 |
在Visual Studio项目中选择.NET Framework版本时,实际上是在设置CLR和BCL的版本,而不是编译器。这意味着可以使用较新的Visual Studio版本编译代码,使其在旧的.NET Framework版本上运行,同时仍然使用新的C#/VB语言特性。例如,使用Visual Studio 2008分发的C# 3.0编译器,可以使用自动属性(编译器生成的属性后端字段),同时生成的输出将在.NET Framework 2.0上运行。
LINQ是.NET Framework 3.5中引入的一个特性,它增加了使用函数式编程风格的能力,并将C#/VB表达式转换为查询语言,如SQL。这需要一些先决条件特性的支持:Lambda表达式、扩展方法、查询语法和表达式树。
Lambda表达式本质上是匿名方法的更简洁语法。在C# 3.0之前,匿名方法的写法如下:
myList.ForEach(
delegate(string x) {
Console.WriteLine(x);
});
现在,可以这样写:
myList.ForEach(x => Console.WriteLine(x));
Lambda表达式是C# 3.0引入的编译器特性,不需要对CLR或BCL进行更改。注意,Lambda版本的代码示例没有显式指定string类型,这是由于类型推断。LINQ利用这一点使长方法链和函数式转换更加易读。
扩展方法允许定义新的方法,这些方法看起来像是现有类型的一部分,而无需修改它们。定义一个常规的静态方法,在静态类中,并使用this关键字注释方法的第一个参数,如下所示:
static class MyExtensions
{
public static int CountOccurencesOfLetter(this string value, char letter)
{
return value.Split(letter).Length - 1;
}
}
现在,任何这种第一个参数类型的实例都似乎有一个方法,其余参数作为实例方法:
string word = "banana";
Console.WriteLine(word.CountOccurencesOfLetter('a'));
扩展方法的调用被C#3.0编译器编译为常规静态方法调用,这使得它成为一种语法糖。BCL中添加了一个新的属性ExtensionAttribute,编译器使用它来标记和检测编译代码中的扩展方法。因此,如果要反编译上面定义的代码,结果将如下所示:
static class MyExtensions
{
[Extension]
public static int CountOccurencesOfLetter(string value, char letter)
{
return value.Split(letter).Length - 1;
}
}
// ...
string word = "banana";
Console.WriteLine(MyExtensions.CountOccurencesOfLetter(word, 'a'));
LINQ使用扩展方法为IEnumerable
查询语法允许用更像SQL的语法替换方法链:
var result = list.Where(x => x.Id > 2).Select(x => x.Name);
可以替换为:
var result = from x in list where x.Id > 2 select x.Name;
这个C# 3.0特性只要list提供适当的方法签名Where()、Select()等(直接或通过扩展方法),就可以工作。它不依赖BCL中的任何特定类型。
表达式树是LINQ的最后一个组成部分。当一个Lambda表达式被分配给一个变量或方法参数类型Expression
现在已经看到了LINQ能为做什么,不想错过它。但对于部署工具,如Zero Install及其引导程序,重要的是EXE能够在尽可能多的机器上即开即用。这意味着仍然有优势将目标定为.NET Framework版本2.0。
幸运的是,可以两全其美。出色的LinqBridge项目将大部分LINQ回溯到.NET 2.0。它通过利用文章开头提到的C#/VB编译器和BCL的独立版本化来实现这一点。当使用依赖BCL类的特性时,编译器不会在特定程序集中查找。相反,它在所有引用的程序集中查找特定的命名空间。LinqBridge库提供了诸如ExtensionAttribute和IEnumerable