C# 语言介绍A tour of the C# language

C#(读作“See Sharp”)是一种新式编程语言,不仅面向对象,还类型安全。C# (pronounced "See Sharp") is a modern, object-oriented, and type-safe programming language. C# 源于 C 语言系列,C、C++、Java 和 JavaScript 程序员很快就可以上手使用。C# has its roots in the C family of languages and will be immediately familiar to C, C++, Java, and JavaScript programmers. 本教程概述了 C# 8 及更高版本中该语言的主要组件。This tour provides an overview of the major components of the language in C# 8 and earlier. 如果想要通过交互式示例探索语言,请尝试 C# 简介教程。If you want to explore the language through interactive examples, try the introduction to C# tutorials.

C# 是面向对象的、面向组件的编程语言。C# is an object-oriented, component-oriented programming language. C# 提供了语言构造来直接支持这些概念,让 C# 成为一种非常自然的语言,可用于创建和使用软件组件。C# provides language constructs to directly support these concepts, making C# a natural language in which to create and use software components. 自诞生之日起,C# 就添加了支持新工作负载和新兴软件设计实践的功能。Since its origin, C# has added features to support new workloads and emerging software design practices.

多项 C# 功能有助于构造可靠耐用的应用程序。Several C# features aid in the construction of robust and durable applications. 垃圾回收会自动回收无法访问的未使用对象所占用的内存。Garbage collection automatically reclaims memory occupied by unreachable unused objects. 异常处理提供了一种结构化且可扩展的方法来进行错误检测和恢复。Exception handling provides a structured and extensible approach to error detection and recovery. Lambda 表达式支持函数编程技术。Lambda expressions support functional programming techniques. 查询语法创建一个公共模式,用于处理来自任何源的数据。Query syntax creates a common pattern for working with data from any source. 异步操作语言支持提供用于构建分布式系统的语法。Language support for asynchronous operations provides syntax for building distributed systems. 模式匹配提供语法,可轻松地将数据从新式分布式系统中的算法中分离出来。Pattern matching provides syntax to easily separate data from algorithms in modern distributed systems. C# 采用统一的类型系统C# has a unified type system. 所有 C# 类型(包括 intdouble 等基元类型)均继承自一个根 object 类型。All C# types, including primitive types such as int and double, inherit from a single root object type. 所有类型共用一组通用运算。All types share a set of common operations. 任何类型的值都可以一致地进行存储、传输和处理。Values of any type can be stored, transported, and operated upon in a consistent manner. 此外,C# 还支持用户定义的引用类型和值类型。Furthermore, C# supports both user-defined reference types and value types. C# 允许动态分配轻型结构的对象和内嵌存储。C# allows dynamic allocation of objects and in-line storage of lightweight structures.

C# 强调版本控制,以确保程序和库以兼容方式随时间推移而变化。C# emphasizes versioning to ensure programs and libraries can evolve over time in a compatible manner. C# 设计中受版本控制加强直接影响的方面包括:单独的 virtualoverride 修饰符,关于方法重载决策的规则,以及对显式接口成员声明的支持。Aspects of C#'s design that were directly influenced by versioning considerations include the separate virtual and override modifiers, the rules for method overload resolution, and support for explicit interface member declarations.

Hello worldHello world

“Hello, World”程序历来都用于介绍编程语言。The "Hello, World" program is traditionally used to introduce a programming language. 下面展示了此程序的 C# 代码:Here it is in C#:

using System;

class Hello
{
    static void Main()
    {
        Console.WriteLine("Hello, World");
    }
}

“Hello, World”程序始于引用 System 命名空间的 using 指令。The "Hello, World" program starts with a using directive that references the System namespace. 命名空间提供了一种用于组织 C# 程序和库的分层方法。Namespaces provide a hierarchical means of organizing C# programs and libraries. 命名空间包含类型和其他命名空间。例如,System 命名空间包含许多类型(如程序中引用的 Console 类)和其他许多命名空间(如 IOCollections)。Namespaces contain types and other namespaces—for example, the System namespace contains a number of types, such as the Console class referenced in the program, and a number of other namespaces, such as IO and Collections. 借助引用给定命名空间的 using 指令,可以非限定的方式使用作为相应命名空间成员的类型。A using directive that references a given namespace enables unqualified use of the types that are members of that namespace. 由于使用 using 指令,因此程序可以使用 Console.WriteLine 作为 System.Console.WriteLine 的简写。Because of the using directive, the program can use Console.WriteLine as shorthand for System.Console.WriteLine.

“Hello, World”程序声明的 Hello 类只有一个成员,即 Main 方法。The Hello class declared by the "Hello, World" program has a single member, the method named Main. Main 方法使用 static 修饰符进行声明。The Main method is declared with the static modifier. 实例方法可以使用关键字 this 引用特定的封闭对象实例,而静态方法则可以在不引用特定对象的情况下运行。While instance methods can reference a particular enclosing object instance using the keyword this, static methods operate without reference to a particular object. 按照约定,Main 静态方法是 C# 程序的入口点。By convention, a static method named Main serves as the entry point of a C# program.

程序的输出是由 System 命名空间中 Console 类的 WriteLine 方法生成。The output of the program is produced by the WriteLine method of the Console class in the System namespace. 此类由标准类库提供。默认情况下,编译器会自动引用标准类库。This class is provided by the standard class libraries, which, by default, are automatically referenced by the compiler.

类型和变量Types and variables

C# 有两种类型:值类型引用类型There are two kinds of types in C#: value types and reference types. 值类型的变量直接包含数据,而引用类型的变量则存储对数据(称为“对象”)的引用。Variables of value types directly contain their data whereas variables of reference types store references to their data, the latter being known as objects. 对于引用类型,两个变量可以引用同一个对象;对一个变量执行的运算可能会影响另一个变量引用的对象。With reference types, it's possible for two variables to reference the same object and possible for operations on one variable to affect the object referenced by the other variable. 借助值类型,每个变量都有自己的数据副本;因此,对一个变量执行的运算不会影响另一个变量(refout 参数变量除外)。With value types, the variables each have their own copy of the data, and it isn't possible for operations on one to affect the other (except for ref and out parameter variables).

标识符为变量名称。An identifier is a variable name. 标识符是不包含任何空格的 unicode 字符序列。An identifier is a sequence of unicode characters without any whitespace. 如果标识符的前缀为 @,则该标识符可以是 C# 保留字。An identifier may be a C# reserved word, if it is prefixed by @. 这在与其他语言交互时非常有用。That can be useful when interacting with other languages.

C# 值类型又细分为简单类型、枚举类型、结构类型、可以为 null 的值类型和元组值类型。C#'s value types are further divided into simple types, enum types, struct types, nullable value types and tuple value types. C# 引用类型又细分为类类型、接口类型、数组类型和委托类型。 C#'s reference types are further divided into class types, interface types, array types, and delegate types.

以下大纲概述了 C# 的类型系统。The following outline provides an overview of C#'s type system.

C# 程序使用类型声明创建新类型。C# programs use type declarations to create new types. 类型声明指定新类型的名称和成员。A type declaration specifies the name and the members of the new type. 用户可定义以下六种 C# 类型:类类型、结构类型、接口类型、枚举类型、委托类型和元组值类型。Six of C#'s categories of types are user-definable: class types, struct types, interface types, enum types, delegate types and tuple value types.

  • class 类型定义包含数据成员(字段)和函数成员(方法、属性及其他)的数据结构。A class type defines a data structure that contains data members (fields) and function members (methods, properties, and others). 类类型支持单一继承和多形性,即派生类可以扩展和专门针对基类的机制。Class types support single inheritance and polymorphism, mechanisms whereby derived classes can extend and specialize base classes.
  • struct 类型定义包含数据成员和函数成员的结构,这一点与类类型相似。A struct type is similar to a class type in that it represents a structure with data members and function members. 不过,与类不同的是,结构是值类型,通常不需要进行堆分配。However, unlike classes, structs are value types and don't typically require heap allocation. 结构类型不支持用户指定的继承,并且所有结构类型均隐式继承自类型 objectStruct types don't support user-specified inheritance, and all struct types implicitly inherit from type object.
  • interface 类型将协定定义为一组已命名的公共成员。An interface type defines a contract as a named set of public members. 实现 interfaceclassstruct 必须提供接口成员的实现代码。A class or struct that implements an interface must provide implementations of the interface's members. interface 可以继承自多个基接口,classstruct 可以实现多个接口。An interface may inherit from multiple base interfaces, and a class or struct may implement multiple interfaces.
  • delegate 类型表示引用包含特定参数列表和返回类型的方法。A delegate type represents references to methods with a particular parameter list and return type. 通过委托,可以将方法视为可分配给变量并可作为参数传递的实体。Delegates make it possible to treat methods as entities that can be assigned to variables and passed as parameters. 委托类同于函数式语言提供的函数类型。Delegates are analogous to function types provided by functional languages. 它们还类似于其他一些语言中存在的“函数指针”概念。They're also similar to the concept of function pointers found in some other languages. 与函数指针不同,委托是面向对象且类型安全的。Unlike function pointers, delegates are object-oriented and type-safe.

classstructinterfacedelegate 类型全部都支持泛型,因此可以使用其他类型对它们进行参数化。The class, struct, interface, and delegate types all support generics, whereby they can be parameterized with other types.

C# 支持任意类型的一维和多维数组。C# supports single-dimensional and multi-dimensional arrays of any type. 与上述类型不同,数组类型无需先声明即可使用。Unlike the types listed above, array types don't have to be declared before they can be used. 相反,数组类型是通过在类型名称后面添加方括号构造而成。Instead, array types are constructed by following a type name with square brackets. 例如,int[]int 类型的一维数组,int[,]int 类型的二维数组,int[][] 是由 int 类型的一维数组或“交错”数组构成的一维数组。For example, int[] is a single-dimensional array of int, int[,] is a two-dimensional array of int, and int[][] is a single-dimensional array of single-dimensional arrays, or a "jagged" array, of int.

可以为 null 的类型不需要单独定义。Nullable types don't require a separate definition. 对于所有不可以为 null 的类型 T,都有对应的可以为 null 的类型 T?,后者可以包含附加值 nullFor each non-nullable type T, there's a corresponding nullable type T?, which can hold an additional value, null. 例如,int? 是可保存任何 32 位整数或 null 值的类型,string? 是可以保存任何 stringnull 值的类型。For instance, int? is a type that can hold any 32-bit integer or the value null, and string? is a type that can hold any string or the value null.

C# 采用统一的类型系统,因此任意类型的值都可视为 objectC#'s type system is unified such that a value of any type can be treated as an object. 每种 C# 类型都直接或间接地派生自 object 类类型,而 object 是所有类型的最终基类。Every type in C# directly or indirectly derives from the object class type, and object is the ultimate base class of all types. 只需将值视为类型 object,即可将引用类型的值视为对象。Values of reference types are treated as objects simply by viewing the values as type object. 通过执行装箱取消装箱操作,可以将值类型的值视为对象。Values of value types are treated as objects by performing boxing and unboxing operations. 在以下示例中,int 值被转换成 object,然后又恢复成 intIn the following example, an int value is converted to object and back again to int.

int i = 123;
object o = i;    // Boxing
int j = (int)o;  // Unboxing

将值类型的值分配给 object 对象引用时,会分配一个“箱”来保存此值。When a value of a value type is assigned to an object reference, a "box" is allocated to hold the value. 该箱是引用类型的实例,此值会被复制到该箱。That box is an instance of a reference type, and the value is copied into that box. 相反,当 object 引用被显式转换成值类型时,将检查引用的 object 是否是具有正确值类型的箱。Conversely, when an object reference is cast to a value type, a check is made that the referenced object is a box of the correct value type. 如果检查成功,则会将箱中的值复制到值类型。If the check succeeds, the value in the box is copied to the value type.

C# 的统一类型系统实际上意味着“按需”将值类型视为 object 引用。C#'s unified type system effectively means that value types are treated as object references "on demand." 鉴于这种统一性,使用类型 object 的常规用途库可以与派生自 object 的所有类型结合使用,包括引用类型和值类型。Because of the unification, general-purpose libraries that use type object can be used with all types that derive from object, including both reference types and value types.

C# 有多种变量,其中包括字段、数组元素、局部变量和参数。There are several kinds of variables in C#, including fields, array elements, local variables, and parameters. 变量表示存储位置。Variables represent storage locations. 每个变量都具有一种类型,用于确定可以在变量中存储哪些值,如下文所述。Every variable has a type that determines what values can be stored in the variable, as shown below.

  • 不可以为 null 的值类型Non-nullable value type
    • 具有精确类型的值A value of that exact type
  • 可以为 null 的值类型Nullable value type
    • null 值或具有精确类型的值A null value or a value of that exact type
  • objectobject
    • null 引用、对任意引用类型的对象的引用,或对任意值类型的装箱值的引用A null reference, a reference to an object of any reference type, or a reference to a boxed value of any value type
  • 类类型Class type
    • null 引用、对类类型实例的引用,或对派生自类类型的类实例的引用A null reference, a reference to an instance of that class type, or a reference to an instance of a class derived from that class type
  • 接口类型Interface type
    • null 引用、对实现接口类型的类类型实例的引用,或对实现接口类型的值类型的装箱值的引用A null reference, a reference to an instance of a class type that implements that interface type, or a reference to a boxed value of a value type that implements that interface type
  • 数组类型Array type
    • null 引用、对数组类型实例的引用,或对兼容的数组类型实例的引用A null reference, a reference to an instance of that array type, or a reference to an instance of a compatible array type
  • 委托类型Delegate type
    • null 引用或对兼容的委托类型实例的引用A null reference or a reference to an instance of a compatible delegate type

程序结构Program structure

C# 中的关键组织结构概念包括程序命名空间类型成员程序集The key organizational concepts in C# are programs, namespaces, types, members, and assemblies. 程序声明类型,而类型则包含成员,并被整理到命名空间中。Programs declare types, which contain members and can be organized into namespaces. 类型示例包括类、结构和接口。Classes, structs, and interfaces are examples of types. 成员示例包括字段、方法、属性和事件。Fields, methods, properties, and events are examples of members. 编译完的 C# 程序实际上会打包到程序集中。When C# programs are compiled, they're physically packaged into assemblies. 程序集的文件扩展名通常为 .exe.dll,具体取决于实现的是应用程序还是Assemblies typically have the file extension .exe or .dll, depending on whether they implement applications or libraries, respectively.

作为一个小示例,请考虑包含以下代码的程序集:As a small example, consider an assembly that contains the following code:

using System;

namespace Acme.Collections
{
    public class Stack<T>
    {
        Entry _top;
        
        public void Push(T data)
        {
            _top = new Entry(_top, data);
        }

        public T Pop()
        {
            if (_top == null)
            {
                throw new InvalidOperationException();
            }
            T result = _top.Data;
            _top = _top.Next;
            
            return result;
        }

        class Entry
        {
            public Entry Next { get; set; }
            public T Data { get; set; }
            
            public Entry(Entry next, T data)
            {
                Next = next;
                Data = data;
            }
        }
    }
}

此类的完全限定的名称为 Acme.Collections.StackThe fully qualified name of this class is Acme.Collections.Stack. 此类包含多个成员:一个 top 字段、两个方法(PushPop)和一个 Entry 嵌套类。The class contains several members: a field named top, two methods named Push and Pop, and a nested class named Entry. Entry 类还包含三个成员:一个 next 字段、一个 data 字段和一个构造函数。The Entry class further contains three members: a field named next, a field named data, and a constructor. Stack 是泛型类。The Stack is a generic class. 它具有一个类型参数 T,在使用时替换为具体类型。It has one type parameter, T that is replaced with a concrete type when it's used.

备注

堆栈是一个“先进后出”(FILO) 集合。A stack is a "first in - last out" (FILO) collection. 添加到堆栈顶部的新元素。New elements are added to the top of the stack. 删除元素时,将从堆栈顶部删除该元素。When an element is removed, it is removed from the top of the stack.

程序集包含中间语言 (IL) 指令形式的可执行代码和元数据形式的符号信息。Assemblies contain executable code in the form of Intermediate Language (IL) instructions, and symbolic information in the form of metadata. 执行前,.NET 公共语言运行时的实时 (JIT) 编译器会将程序集中的 IL 代码转换为特定于处理器的代码。Before it's executed, the Just-In-Time (JIT) compiler of .NET Common Language Runtime converts the IL code in an assembly to processor-specific code.

由于程序集是包含代码和元数据的自描述功能单元,因此无需在 C# 中使用 #include 指令和头文件。Because an assembly is a self-describing unit of functionality containing both code and metadata, there's no need for #include directives and header files in C#. 只需在编译程序时引用特定的程序集,即可在 C# 程序中使用此程序集中包含的公共类型和成员。The public types and members contained in a particular assembly are made available in a C# program simply by referencing that assembly when compiling the program. 例如,此程序使用 acme.dll 程序集中的 Acme.Collections.Stack 类:For example, this program uses the Acme.Collections.Stack class from the acme.dll assembly:

using System;
using Acme.Collections;

class Example
{
    public static void Main()
    {
        var s = new Stack<int>();
        s.Push(1); // stack contains 1
        s.Push(10); // stack contains 1, 10
        s.Push(100); // stack contains 1, 10, 100
        Console.WriteLine(s.Pop()); // stack contains 1, 10
        Console.WriteLine(s.Pop()); // stack contains 1
        Console.WriteLine(s.Pop()); // stack is empty
    }
}

若要编译此程序,需要引用包含前面示例中定义的堆栈类的程序集。To compile this program, you would need to reference the assembly containing the stack class defined in the earlier example.

C# 程序可以存储在多个源文件中。C# programs can be stored in several source files. 在编译 C# 程序时,将同时处理所有源文件,并且源文件可以自由地相互引用。When a C# program is compiled, all of the source files are processed together, and the source files can freely reference each other. 从概念上讲,就好像所有源文件在被处理之前都连接到一个大文件。Conceptually, it's as if all the source files were concatenated into one large file before being processed. 在 C# 中永远都不需要使用前向声明,因为声明顺序无关紧要(极少数例外情况除外)。Forward declarations are never needed in C# because, with few exceptions, declaration order is insignificant. C# 并不限制源文件只能声明一种公共类型,也不要求源文件的文件名必须与其中声明的类型相匹配。C# doesn't limit a source file to declaring only one public type nor does it require the name of the source file to match a type declared in the source file.

本教程中的后续文章介绍了这些组织块。Further articles in this tour explain these organizational blocks.