C# 语言介绍

C# 语言是适用于 .NET 平台(免费的跨平台开源开发环境)的最流行语言。 C# 程序可以在许多不同的设备上运行,从物联网 (IoT) 设备到云以及介于两者之间的任何设备。 可为手机、台式机、笔记本电脑和服务器编写应用。

C# 是一种跨平台的通用语言,可以让开发人员在编写高性能代码时提高工作效率。 C# 是数百万开发人员中最受欢迎的 .NET 语言。 C# 在生态系统和所有 .NET 工作负载中具有广泛的支持。 基于面向对象的原则,它融合了其他范例中的许多功能,尤其是函数编程。 低级功能支持高效方案,无需编写不安全的代码。 大多数 .NET 运行时和库都是用 C# 编写的,C# 的进步通常会使所有 .NET 开发人员受益。

C# 属于 C 语言家族。 如果使用 C、C++、JavaScript、TypeScript 或 Java,则 C# 语法很熟悉。 与 C 和 C++ 一样,分号 (;) 定义语句的末尾。 C# 标识符区分大小写。 C# 同样使用大括号({})、控制语句(例如 ifelseswitch)以及循环结构(例如 forwhile)。 C# 还具有适用于任何集合类型的 foreach 语句。

世界您好

“Hello, World”程序历来都用于介绍编程语言。 下面展示了此程序的 C# 代码:

// This line prints "Hello, World" 
Console.WriteLine("Hello, World");

// 开头的行是单行注释。 C# 单行注释以 // 开头,持续到当前行的末尾。 C# 还支持多行注释。 多行注释以 /* 开头,以 */ 结尾。 WriteLine 命名空间中的 Console 类的 System 方法生成程序的输出。 此类由标准类库提供,默认情况下,每个 C# 程序中会自动引用这些库。 另一种程序形式要求你声明程序入口点所在的类和方法。 使用顶级语句时,编译器会合成这些元素。

此替代格式仍然有效,并且包含所有 C# 程序中的许多基本概念。 许多现有的 C# 示例使用以下等效格式:

using System;
namespace TourOfCsharp;

class Program
{
    static void Main()
    {
        // This line prints "Hello, World" 
        Console.WriteLine("Hello, World");
    }
}

前面的“Hello, World”程序以 using 指令开头,该指令用于引用 System 命名空间。 命名空间提供了一种用于组织 C# 程序和库的分层方法。 命名空间包含类型和其他命名空间。例如,System 命名空间包含许多类型(如程序中引用的 Console 类)和其他许多命名空间(如 IOCollections)。 借助引用给定命名空间的 using 指令,可以非限定的方式使用作为相应命名空间成员的类型。 由于使用 using 指令,因此程序可以使用 Console.WriteLine 作为 System.Console.WriteLine 的简写。 在前面的示例中,该命名空间是隐式包含的。

“Hello, World”程序声明的 Program 类只有一个成员,即 Main 方法。 Main 方法使用 static 修饰符进行声明。 实例方法可以使用关键字 this 引用特定的封闭对象实例,而静态方法则可以在不引用特定对象的情况下运行。 按照惯例,当没有顶级语句时,名为 Main 的静态方法将充当 C# 程序的入口点。 包含该方法的 Main 类通常命名 Program

提示

本文中的示例帮助你初步了解 C# 代码。 某些示例可能显示你不熟悉的 C# 元素。 当准备好学习 C# 时,请从我们的初学者教程开始,或通过每个部分中的链接学习深度知识。 如果你在 JavaJavaScriptTypeScriptPython 方面有经验,请阅读我们的提示,帮助你找到快速学习 C# 所需的信息。

熟悉的 C# 功能

C# 对于初学者而言很容易上手,但同时也为经验丰富的专业应用程序开发人员提供了高级功能。 你很快就能提高工作效率。 你可以根据应用程序的需要学习更专业的技术。

C# 应用受益于 .NET 运行时的自动内存管理。 C# 应用还可以使用 .NET SDK 提供的丰富运行时库。 有些组件独立于平台,例如文件系统库、数据集合与数学库。 还有一些组件特定于单个工作负载,例如 ASP.NET Core Web 库或 .NET MAUI UI 库。 NuGet 的丰富开源生态系统增强了作为运行时一部分的库。 这些库提供更多可用的组件。

C# 是一种强类型语言。 声明的每个变量都有一个在编译时已知的类型。 编译器或编辑工具会告诉你是否错误地使用了该类型。 可以在运行程序之前修复这些错误。 以下基础数据类型内置于语言和运行时中:值类型(例如 intdoublechar)、引用类型(例如 string)、数组和其他集合。 编写程序时,你会创建自己的类型。 这些类型可以是值的 struct 类型,也可以是定义面向对象的行为的 class 类型。 可以将 record 修饰符添加到 structclass 类型,以便编译器合成用于执行相等性比较的代码。 还可以创建 interface 定义,用于定义实现该接口的类型必须提供的协定或一组成员。 还可以定义泛型类型和方法。 泛型使用类型参数为使用的实际类型提供占位符

编写代码时,可以将函数(也称为方法)定义为 structclass 类型的成员。 这些方法定义类型的行为。 可以使用不同数量或类型的参数来重载方法。 方法可以选择性地返回一个值。 除了方法之外,C# 类型还可以带有属性,即由称作访问器的函数支持的数据元素。 C# 类型可以定义事件,从而允许类型向订阅者通知重要操作。 C# 支持面向对象的技术,例如 class 类型的继承和多形性。

C# 应用使用异常来报告和处理错误。 如果使用C++或 Java,则这种做法很熟悉。 当无法执行预期的操作时,代码会引发异常。 其他代码(无论位于调用堆栈上面的多少个级别)可以选择性地使用 try - catch 块进行恢复。

独特的 C# 功能

你可能不太熟悉 C# 的某些元素。

C# 提供模式匹配。 这些表达式使你能够检查数据并根据其特征做出决策。 模式匹配为基于数据的控制流提供了极好的语法。 以下代码演示如何使用模式匹配语法来表达布尔 and、or 和 xor 运算的方法

public static bool Or(bool left, bool right) =>
    (left, right) switch
    {
        (true, true) => true,
        (true, false) => true,
        (false, true) => true,
        (false, false) => false,
    };

public static bool And(bool left, bool right) =>
    (left, right) switch
    {
        (true, true) => true,
        (true, false) => false,
        (false, true) => false,
        (false, false) => false,
    };
public static bool Xor(bool left, bool right) =>
    (left, right) switch
    {
        (true, true) => false,
        (true, false) => true,
        (false, true) => true,
        (false, false) => false,
    };

可以通过对任何值统一使用 _ 来简化模式匹配表达式。 以下示例演示如何简化 and 方法

public static bool ReducedAnd(bool left, bool right) =>
    (left, right) switch
    {
        (true, true) => true,
        (_, _) => false,
    };

前面的示例还声明 元组、轻型数据结构。 元组是具有可选名称和单个类型的有序固定长度值序列。 将序列括在 () 标签中。 声明 (left, right) 定义一个元组,其中包含两个布尔值: leftright。 每个 switch 臂都声明元组值,例如 (true, true)。 元组提供方便的语法来声明具有多个值的单个值。

集合表达式 提供用于提供集合值的通用语法。 在字符之间[]写入值或表达式,编译器将该表达式转换为所需的集合类型:

int[] numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
List<string> names = ["Alice", "Bob", "Charlie", "David"];

IEnumerable<int> moreNumbers = [.. numbers, 11, 12, 13];
IEnumerable<string> empty = [];

前面的示例显示了可以使用集合表达式初始化的不同集合类型。 一个示例使用 [] 空集合表达式来声明空集合。 另一个示例使用 ..spread 元素 展开集合并将其所有值添加到集合表达式。

可以使用 索引范围 表达式从可索引集合中检索一个或多个元素:

string second = names[1]; // 0-based index
string last = names[^1]; // ^1 is the last element
int[] smallNumbers = numbers[0..5]; // 0 to 4

^ 索引表示从末尾而不是从头开始。 ^0 元素位于集合的末尾之后,因此 ^1 是最后一个元素。 在范围表达式 .. 中表示要包含的元素范围。 范围从第一个索引开始,并包含所有元素,直到最后一个索引处的元素(但不包括该元素)。

语言集成查询 (LINQ) 提供一种基于模式的通用语法来查询或转换任何数据集合。 LINQ 统一了查询内存中集合、结构化数据(例如 XML 或 JSON)、数据库存储,甚至基于云的数据 API 的语法。 你只需学习一套语法即可搜索和操作数据,无论其存储在何处。 以下查询查找平均学分大于 3.5 的所有学生:

var honorRoll = from student in Students
                where student.GPA > 3.5
                select student;

上面的查询适用于 Students 表示的许多存储类型。 它可以是对象的集合、数据库表、云存储 Blob 或 XML 结构。 相同的查询语法适用于所有存储类型。

使用基于任务的异步编程模型,可以编写看起来像是同步运行的代码,即使它是异步运行的。 它利用 asyncawait 关键字来描述异步方法,以及表达式何时进行异步计算。 以下示例等待异步 Web 请求。 异步操作完成后,该方法返回响应的长度:

public static async Task<int> GetPageLengthAsync(string endpoint)
{
    var client = new HttpClient();
    var uri = new Uri(endpoint);
    byte[] content = await client.GetByteArrayAsync(uri);
    return content.Length;
}

C# 还支持使用 await foreach 语句来迭代由异步操作支持的集合,例如 GraphQL 分页 API。 以下示例以块的形式读取数据,并返回一个迭代器,该迭代器提供对每个可用元素的访问:

public static async IAsyncEnumerable<int> ReadSequence()
{
    int index = 0;
    while (index < 100)
    {
        int[] nextChunk = await GetNextChunk(index);
        if (nextChunk.Length == 0)
        {
            yield break;
        }
        foreach (var item in nextChunk)
        {
            yield return item;
        }
        index++;
    }
}

调用方可以使用 await foreach 语句迭代该集合:

await foreach (var number in ReadSequence())
{
    Console.WriteLine(number);
}

最后,作为 .NET 生态系统的一部分,你可以将 Visual StudioVisual Studio CodeC# DevKit 配合使用。 这些工具可以全方位地理解 C# 语言,包括你编写的代码。 它们还提供调试功能。