簡介Introduction

C# (發音為 "See Sharp") 是簡單、物件導向、型別安全的現代化程式設計語言。C# (pronounced "See Sharp") is a simple, modern, object-oriented, and type-safe programming language. C # 在 C 系列語言中有其根目錄,並且會立即熟悉 C、c + + 和 JAVA 程式設計人員。C# has its roots in the C family of languages and will be immediately familiar to C, C++, and Java programmers. C # 是由 ECMA 國際標準化為 ecma-334 _ standard,而 ISO/iec 則是 _ iso/iec 23270 標準。C# is standardized by ECMA International as the ECMA-334 _ standard and by ISO/IEC as the _ ISO/IEC 23270 standard. 適用于 .NET Framework 的 Microsoft c # 編譯器是這兩種標準的符合規範。Microsoft's C# compiler for the .NET Framework is a conforming implementation of both of these standards.

C# 是物件導向的語言,但 C# 更進一步支援「元件導向」程式設計。C# is an object-oriented language, but C# further includes support for component-oriented programming. 現代軟體設計逐漸依賴功能性上獨立與屬於自我描述套件的軟體元件。Contemporary software design increasingly relies on software components in the form of self-contained and self-describing packages of functionality. 這類元件的關鍵在於它們呈現含有屬性、方法和事件的程式設計模型;它們提供元件相關宣告資訊的屬性,且併入自己的文件。Key to such components is that they present a programming model with properties, methods, and events; they have attributes that provide declarative information about the component; and they incorporate their own documentation. C # 提供語言結構來直接支援這些概念,因此 c # 是一種非常自然的語言,可在其中建立和使用軟體元件。C# provides language constructs to directly support these concepts, making C# a very natural language in which to create and use software components.

有幾個 c # 功能有助於構建強大且持久的應用程式: 垃圾收集 _ 會自動回收未使用的物件所佔用的記憶體; _例外狀況處理_ 提供結構化且可擴充的方法來偵測和復原錯誤;而語言的 _ 型別安全 設計,使得無法從未初始化的變數讀取、將陣列的索引超出其界限,或執行未檢查的型別轉換。Several C# features aid in the construction of robust and durable applications: Garbage collection _ automatically reclaims memory occupied by unused objects; _exception handling_ provides a structured and extensible approach to error detection and recovery; and the _ type-safe design of the language makes it impossible to read from uninitialized variables, to index arrays beyond their bounds, or to perform unchecked type casts.

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. 因此,所有型別都擁有相同的一組常見作業,且任何型別的值都能以相同方式儲存、傳送及操作。Thus, all types share a set of common operations, and 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, allowing dynamic allocation of objects as well as in-line storage of lightweight structures.

為了確保 c # 程式和程式庫能夠以相容的方式在一段時間內演進,在 c # 設計中的 版本 設定方面已有許多強調。To ensure that C# programs and libraries can evolve over time in a compatible manner, much emphasis has been placed on versioning in C#'s design. 許多程式設計語言並不注重此問題,因此當推出新版的相依程式庫時,以那些語言撰寫的程式需要進行較多修改才能繼續運作。Many programming languages pay little attention to this issue, and, as a result, programs written in those languages break more often than necessary when newer versions of dependent libraries are introduced. C # 的設計方面,直接受到版本控制考慮的影響包括個別 virtual 和修飾詞 override 、方法多載解析的規則,以及對明確介面成員宣告的支援。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.

本章的其餘部分將說明 c # 語言的基本功能。The rest of this chapter describes the essential features of the C# language. 雖然稍後的章節會以詳細導向的方式和有時的數學方式來描述規則和例外狀況,但這一章會為您提供更清楚和簡潔的功能,但代價是完整性。Although later chapters describe rules and exceptions in a detail-oriented and sometimes mathematical manner, this chapter strives for clarity and brevity at the expense of completeness. 其目的是要為讀者提供語言簡介,以加速撰寫早期程式和閱讀後續章節。The intent is to provide the reader with an introduction to the language that will facilitate the writing of early programs and the reading of later chapters.

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");
    }
}

C# 原始程式檔的副檔名通常是 .csC# source files typically have the file extension .cs. 假設 "Hello,World" 程式儲存在檔案中 hello.cs ,則可以使用命令列以 Microsoft c # 編譯器來編譯器Assuming that the "Hello, World" program is stored in the file hello.cs, the program can be compiled with the Microsoft C# compiler using the command line

csc hello.cs

這會產生名為的可執行元件 hello.exewhich produces an executable assembly named hello.exe. 執行此應用程式時所產生的輸出為The output produced by this application when it is run is

Hello, World

“Hello, World” 程式的開頭為 using 指示詞,會參考 System 命名空間。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使用修飾詞宣告方法 staticThe 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 的靜態方法做為程式的進入點。By convention, a static method named Main serves as the entry point of a program.

程式的輸出是由 System 命名空間中 Console 類別的 WriteLine 方法產生。The output of the program is produced by the WriteLine method of the Console class in the System namespace. 這個類別是由 .NET Framework 類別庫所提供,這些程式庫預設是由 Microsoft c # 編譯器自動參考。This class is provided by the .NET Framework class libraries, which, by default, are automatically referenced by the Microsoft C# compiler. 請注意,c # 本身沒有個別的執行時間程式庫。Note that C# itself does not have a separate runtime library. 相反地,.NET Framework 是 c # 的執行時間程式庫。Instead, the .NET Framework is the runtime library of C#.

程式結構Program structure

C # 中的重要組織概念有 程式 _ _、命名空間_、 _類型_、 _成員_ 和 _元件*The key organizational concepts in C# are programs _, _namespaces*, types, members, and *assemblies*. C# 程式包含一個或多個原始程式檔。C# programs consist of one or more source files. 程式宣告型別,其中包含成員並可以依據命名空間分組。Programs declare types, which contain members and can be organized into namespaces. 類別和介面都是型別的範例。Classes and interfaces are examples of types. 欄位、方法、屬性及事件都是成員的範例。Fields, methods, properties, and events are examples of members. 在編譯 C# 語言時,會將它們實際封裝為組件。When C# programs are compiled, they are physically packaged into assemblies. 元件通常會有副檔名 .exe.dll ,視它們是否會執行 *應用程式* 或 _ * 連結 * * 而定。Assemblies typically have the file extension .exe or .dll, depending on whether they implement applications or _*libraries**.

範例The example

using System;

namespace Acme.Collections
{
    public class Stack
    {
        Entry top;

        public void Push(object data) {
            top = new Entry(top, data);
        }

        public object Pop() {
            if (top == null) throw new InvalidOperationException();
            object result = top.data;
            top = top.next;
            return result;
        }

        class Entry
        {
            public Entry next;
            public object data;
    
            public Entry(Entry next, object data) {
                this.next = next;
                this.data = data;
            }
        }
    }
}

宣告 Stack 命名空間中名為的類別 Acme.Collectionsdeclares a class named Stack in a namespace called Acme.Collections. 此類別的完整名稱是 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. 假設此範例的原始程式碼儲存在檔案 acme.cs,命令列Assuming that the source code of the example is stored in the file acme.cs, the command line

csc /t:library acme.cs

會將範例編譯為程式庫 (不需要 Main 進入點的程式碼),並產生名為 acme.dll 的組件。compiles the example as a library (code without a Main entry point) and produces an assembly named acme.dll.

元件包含 *中繼語言 _ (IL) 指令和符號資訊(格式為 _ metadata *)的可執行程式碼。Assemblies contain executable code in the form of Intermediate Language _ (IL) instructions, and symbolic information in the form of _metadata**. 執行前,組件中的 IL 程式碼會由 .NET 通用語言執行平台的 Just-In-Time (JIT) 編譯器自動轉換為處理器特定程式碼。Before it is executed, the IL code in an assembly is automatically converted to processor-specific code by the Just-In-Time (JIT) compiler of .NET Common Language Runtime.

由於組件是包含程式碼和中繼資料的功能自我描述單位,所以不需要提供 C# 中的 #include 指示詞和標頭檔。Because an assembly is a self-describing unit of functionality containing both code and metadata, there is 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 Test
{
    static void Main() {
        Stack s = new Stack();
        s.Push(1);
        s.Push(10);
        s.Push(100);
        Console.WriteLine(s.Pop());
        Console.WriteLine(s.Pop());
        Console.WriteLine(s.Pop());
    }
}

如果程式儲存在檔案中,則 test.cs 編譯時 test.csacme.dll 可以使用編譯器的選項參考元件 /rIf the program is stored in the file test.cs, when test.cs is compiled, the acme.dll assembly can be referenced using the compiler's /r option:

csc /r:acme.dll test.cs

這樣會建立名為 test.exe 可執行檔組件,執行時會產生以下輸出︰This creates an executable assembly named test.exe, which, when run, produces the output:

100
10
1

C# 允許以數個原始程式檔儲存程式的原始程式文字。C# permits the source text of a program to be stored in several source files. 編譯有多檔案的 C# 程式時,所有原始程式檔都會一起處理,而原始程式檔可以隨意地互相參考。概念上,就如同將所有原始程式檔都串連成一個大型檔案,然後再進行處理。When a multi-file C# program is compiled, all of the source files are processed together, and the source files can freely reference each other—conceptually, it is 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 very few exceptions, declaration order is insignificant. C# 不會限制原始程式檔只能宣告一個公用型別,也不會要求原始程式檔符合原始程式檔中所宣告的型別名稱。C# does not 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.

型別與變數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 is possible for two variables to reference the same object and thus 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 is not possible for operations on one to affect the other (except in the case of ref and out parameter variables).

C # 的實值型別會進一步分成 簡單類型 _、 _列舉_ 型別、 _結構類型_ 和 _可為 Null_ 的型別,而 c # 的參考型別則會進一步分割成 _類別類型_、 _介面類別型_、 _陣列*_ 型別和 _ *委派 型別 * *。C#'s value types are further divided into simple types _, _enum types_, _struct types_, and _nullable types_, and C#'s reference types are further divided into _class types_, _interface types_, _array types_, and _delegate types**.

下表概要說明 c # 的型別系統。The following table provides an overview of C#'s type system.

類別Category 說明Description
值類型Value types 簡單型別Simple types 帶正負號的整數︰sbyteshortintlongSigned integral: sbyte, short, int, long
不帶正負號的整數︰byteushortuintulongUnsigned integral: byte, ushort, uint, ulong
Unicode 字元:charUnicode characters: char
IEEE 浮點數:floatdoubleIEEE floating point: float, double
高精確度十進位︰decimalHigh-precision decimal: decimal
布林值:boolBoolean: bool
列舉型別Enum types 使用者定義型別,格式為 enum E {...}User-defined types of the form enum E {...}
結構型別Struct types 使用者定義型別,格式為 struct S {...}User-defined types of the form struct S {...}
可為 Null 的型別Nullable types 含有 null 值的所有其他數值型別的擴充Extensions of all other value types with a null value
參考型別Reference types 類別類型Class types 所有其他型別的基底類別︰objectUltimate base class of all other types: object
Unicode 字串:stringUnicode strings: string
使用者定義型別,格式為 class C {...}User-defined types of the form class C {...}
介面型別Interface types 使用者定義型別,格式為 interface I {...}User-defined types of the form interface I {...}
陣列型別Array types 單一維度和多維度,例如 int[]int[,]Single- and multi-dimensional, for example, int[] and int[,]
委派型別Delegate types 表單的使用者定義類型,例如 delegate int D(...)User-defined types of the form e.g. delegate int D(...)

八種整數型別支援 8 位元、16 位元、32 位元和 64 位元的值 (帶正負號或不帶正負號)。The eight integral types provide support for 8-bit, 16-bit, 32-bit, and 64-bit values in signed or unsigned form.

這兩個浮點數型別 floatdouble 都是使用32位單精確度和64位雙精確度 IEEE 754 格式來表示。The two floating point types, float and double, are represented using the 32-bit single-precision and 64-bit double-precision IEEE 754 formats.

decimal 型別是 128 位元的資料型別,適合財務和貨幣計算。The decimal type is a 128-bit data type suitable for financial and monetary calculations.

C # 的 bool 型別是用來代表布林值,也就是或的值 true falseC#'s bool type is used to represent boolean values—values that are either true or false.

C# 中的字元和字串處理使用 Unicode 編碼方式。Character and string processing in C# uses Unicode encoding. char 型別代表 UTF-16 程式碼單位,而 string 型別代表一系列的 UTF-16 程式碼單位。The char type represents a UTF-16 code unit, and the string type represents a sequence of UTF-16 code units.

下表摘要說明 c # 的數數值型別。The following table summarizes C#'s numeric types.

類別Category BitsBits 型別Type 範圍/有效位數Range/Precision
帶正負號的整數Signed integral 88 sbyte -128 ... 127-128...127
1616 short -32768 ... 32,767-32,768...32,767
3232 int -2147483648 ... 2,147,483,>647-2,147,483,648...2,147,483,647
6464 long -9223372036854775808 ... 9、223、372、036、854、775、807-9,223,372,036,854,775,808...9,223,372,036,854,775,807
不帶正負號的整數Unsigned integral 88 byte 0 ... 2550...255
1616 ushort 0 ... 65,5350...65,535
3232 uint 0 ... 4、294、967、,0...4,294,967,295
6464 ulong 0 ... 18、446、744、073、709、551、6150...18,446,744,073,709,551,615
浮點Floating point 3232 float 1.5 × 10 ^ −45至3.4 × 10 ^ 38,7位數精確度1.5 × 10^−45 to 3.4 × 10^38, 7-digit precision
6464 double 5.0 × 10 ^ −324至1.7 × 10 ^ 308,15位數精確度5.0 × 10^−324 to 1.7 × 10^308, 15-digit precision
DecimalDecimal 128128 decimal 1.0 × 10 ^ −28至7.9 × 10 ^ 28,28位數精確度1.0 × 10^−28 to 7.9 × 10^28, 28-digit precision

C# 程式使用 型別宣告 來建立新型別。C# programs use type declarations to create new types. 型別宣告指定新型別的名稱成員。A type declaration specifies the name and the members of the new type. 有五種類型的 c # 類別可供使用者定義:類別類型、結構類型、介面類別型、列舉類型和委派類型。Five of C#'s categories of types are user-definable: class types, struct types, interface types, enum types, and delegate types.

類別型別會定義資料結構,其中包含 (欄位) 和函式成員 (方法、屬性和其他) 的資料成員。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.

結構類型類似于類別型別,因為它代表具有資料成員和函數成員的結構。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 do not require heap allocation. 結構型別不支援使用者指定的繼承,且所有結構型別都隱含地繼承自 object 型別。Struct types do not support user-specified inheritance, and all struct types implicitly inherit from type object.

介面型別會將合約定義為公用函式成員的命名集。An interface type defines a contract as a named set of public function members. 實介面的類別或結構必須提供介面函式成員的實作為。A class or struct that implements an interface must provide implementations of the interface's function members. 介面可以繼承自多個基底介面,而類別或結構可能會執行多個介面。An interface may inherit from multiple base interfaces, and a class or struct may implement multiple interfaces.

「委派型別」代表對方法的參考,其中含有特定參數清單與傳回型別。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 similar to the concept of function pointers found in some other languages, but unlike function pointers, delegates are object-oriented and type-safe.

類別、結構、介面和委派類型全都支援泛型,因此可以使用其他類型進行參數化。Class, struct, interface and delegate types all support generics, whereby they can be parameterized with other types.

列舉型別是具有命名常數的相異型別。An enum type is a distinct type with named constants. 每個列舉類型都具有基礎類型,必須是八個整數類型的其中一個。Every enum type has an underlying type, which must be one of the eight integral types. 列舉型別的值集合與基礎型別的值組相同。The set of values of an enum type is the same as the set of values of the underlying type.

C# 支援任何型別的單一維度及多維陣列。C# supports single- and multi-dimensional arrays of any type. 不同於上述型別,陣列型別不需宣告即可使用。Unlike the types listed above, array types do not 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[][] 維陣列 intFor 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 of int.

可為 null 的類型也不需要先宣告,就可以使用。Nullable types also do not have to be declared before they can be used. 針對每一個不可為 null 的實值型 T 別,都有一個對應的可為 null 型 T? 別,可以保留額外的值 nullFor each non-nullable value type T there is a corresponding nullable type T?, which can hold an additional value null. 例如, int? 是可以保留任何32位整數或值的型別 nullFor instance, int? is a type that can hold any 32 bit integer or the value null.

C # 的型別系統是統一的,讓任何型別的值都可以當做物件來處理。C#'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.

using System;

class Test
{
    static void Main() {
        int i = 123;
        object o = i;          // Boxing
        int j = (int)o;        // Unboxing
    }
}

當實值型別的值轉換成類型時 object ,會設定物件實例(也稱為「方塊」)來保存值,並將該值複製到該方塊中。When a value of a value type is converted to type object, an object instance, also called a "box," is allocated to hold the value, and the value is copied into that box. 相反地,當 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, and, if the check succeeds, the value in the box is copied out.

C # 的統一型別系統可有效地表示實值型別可以「依需求」變成物件。C#'s unified type system effectively means that value types can become objects "on demand." 因為整合,使用 object 型別的一般用途程式庫就能搭配參考型別和實值型別使用。Because of the unification, general-purpose libraries that use type object can be used with 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, and every variable has a type that determines what values can be stored in the variable, as shown by the following table.

變數類型Type of Variable 可能的內容Possible Contents
不可為 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
object 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 that delegate type

運算式Expressions

運算式 _ 是由 _運算元_ 和 _運算子*_ 所構成。Expressions _ are constructed from _operands_ and _operators*_. 運算式的運算子會指出要將哪些運算套用到運算元。The operators of an expression indicate which operations to apply to the operands. 運算子範例包括 +-_/newExamples of operators include +, -, _, /, and new. 運算元範例包括常值、欄位、區域變數及運算式。Examples of operands include literals, fields, local variables, and expressions.

當運算式包含多個運算子時,運算子的 *優先順序 _ 會控制個別運算子的評估順序。When an expression contains multiple operators, the *precedence _ of the operators controls the order in which the individual operators are evaluated. 例如,運算式 x + y _ z 會評估為 x + (y * z),因為 * 運算子的優先順序高於 + 運算子。For example, the expression x + y _ z is evaluated as x + (y * z) because the * operator has higher precedence than the + operator.

大部分的運算子都可以「多載」。Most operators can be overloaded. 運算子多載可允許針對一個運算元屬於 (或兩個運算元都屬於) 使用者定義之類別或結構型別的運算式,指定使用者定義的運算子實作。Operator overloading permits user-defined operator implementations to be specified for operations where one or both of the operands are of a user-defined class or struct type.

下表摘要說明 c # 的運算子,並依優先順序從最高到最低的順序列出運算子類別目錄。The following table summarizes C#'s operators, listing the operator categories in order of precedence from highest to lowest. 相同類別中的運算子擁有相同優先順序。Operators in the same category have equal precedence.

類別Category 運算式Expression 說明Description
主要Primary x.m 成員存取Member access
x(...) 方法和委派叫用Method and delegate invocation
x[...] 陣列和索引子存取Array and indexer access
x++ 後置遞增Post-increment
x-- 後置遞減Post-decrement
new T(...) 建立物件和委派Object and delegate creation
new T(...){...} 使用初始設定式來建立物件Object creation with initializer
new {...} 匿名物件初始設定式Anonymous object initializer
new T[...] 建立陣列Array creation
typeof(T) 取得 TSystem.Type 物件Obtain System.Type object for T
checked(x) 在核取的內容中評估運算式Evaluate expression in checked context
unchecked(x) 在未核取的內容中評估運算式Evaluate expression in unchecked context
default(T) 取得類型 T 的預設值Obtain default value of type T
delegate {...} 匿名函式 (匿名方法)Anonymous function (anonymous method)
一元 (Unary)Unary +x 身分識別Identity
-x 否定Negation
!x 邏輯否定Logical negation
~x 位元否定Bitwise negation
++x 前置遞增Pre-increment
--x 前置遞減Pre-decrement
(T)x x 明確轉換成類型 TExplicitly convert x to type T
await x 以非同步方式等候 x 完成Asynchronously wait for x to complete
乘法Multiplicative x * y 乘法Multiplication
x / y 除法Division
x % y 餘數Remainder
加法Additive x + y 加法、字串串連、委派組合Addition, string concatenation, delegate combination
x - y 減法、委派移除Subtraction, delegate removal
ShiftShift x << y 左移Shift left
x >> y 右移Shift right
關係和型別測試Relational and type testing x < y 小於Less than
x > y 大於Greater than
x <= y 小於或等於Less than or equal
x >= y 大於或等於Greater than or equal
x is T 如果 xT,便傳回 true,否則傳回 falseReturn true if x is a T, false otherwise
x as T 傳回歸類為 T 類型的 x,或在 x 不是 T 的情況下傳回 nullReturn x typed as T, or null if x is not a T
等式Equality x == y 等於Equal
x != y 不等於Not equal
邏輯 ANDLogical AND x & y 整數位元 AND、布林邏輯 ANDInteger bitwise AND, boolean logical AND
邏輯 XORLogical XOR x ^ y 整數位元 XOR、布林邏輯 XORInteger bitwise XOR, boolean logical XOR
邏輯 ORLogical OR x | y 整數位元 OR、布林邏輯 ORInteger bitwise OR, boolean logical OR
條件式 ANDConditional AND x && y y只有 x 在為時,才會評估trueEvaluates y only if x is true
條件式 ORConditional OR x || y y只有 x 在為時,才會評估falseEvaluates y only if x is false
Null 聯合Null coalescing x ?? y y如果 x 為,則評估為 nullx 否則為Evaluates to y if x is null, to x otherwise
條件式Conditional x ? y : z 如果 xtrue,便評估 y,如果 xfalse,則評估 zEvaluates y if x is true, z if x is false
指派或匿名函式Assignment or anonymous function x = y 指派Assignment
x op= y 複合指派;支援的運算子 *= /= %= += -=<<= >>= &= ^=|=Compound assignment; supported operators are *= /= %= += -= <<= >>= &= ^= |=
(T x) => y 匿名函式 (Lambda 運算式)Anonymous function (lambda expression)

陳述式Statements

程式的動作是藉由 陳述式 來表達。The actions of a program are expressed using statements. C# 支援數種不同類型的陳述式,其中一些是以內嵌陳述式來定義。C# supports several different kinds of statements, a number of which are defined in terms of embedded statements.

「區塊」可允許在許可單一陳述式的內容中撰寫多個陳述式。A block permits multiple statements to be written in contexts where a single statement is allowed. 區塊是由在 {} 分隔符號之間撰寫的陳述式清單所組成。A block consists of a list of statements written between the delimiters { and }.

「宣告陳述式」可用來宣告區域變數和常數。Declaration statements are used to declare local variables and constants.

「運算式陳述式」可用來評估運算式。Expression statements are used to evaluate expressions. 可以當做語句使用的運算式包括方法叫用、使用運算子的物件配置 new 、使用 = 和複合指派運算子的指派、使用 ++ and -- 運算子和 await 運算式的遞增和遞減運算。Expressions that can be used as statements include method invocations, object allocations using the new operator, assignments using = and the compound assignment operators, increment and decrement operations using the ++ and -- operators and await expressions.

「選取範圍陳述式」可用來選取一些可能陳述式的其中之一,以根據某個運算式的值來執行。Selection statements are used to select one of a number of possible statements for execution based on the value of some expression. 在此群組中的是 ifswitch 陳述式。In this group are the if and switch statements.

反復專案 語句 是用來重複執行內嵌語句。Iteration statements are used to repeatedly execute an embedded statement. 在此群組中的是 whiledoforforeach 陳述式。In this group are the while, do, for, and foreach statements.

「跳躍陳述式」可用來轉移控制項。Jump statements are used to transfer control. 在此群組中的是 breakcontinuegotothrowreturnyield 陳述式。In this group are the break, continue, goto, throw, return, and yield statements.

try...catch 陳述式可用來攔截在執行區塊時發生的例外狀況,而 try...finally 陳述式則可用來指定不論是否發生例外狀況都一律會執行的最終處理程式碼。The try...catch statement is used to catch exceptions that occur during execution of a block, and the try...finally statement is used to specify finalization code that is always executed, whether an exception occurred or not.

checkedunchecked 語句用來控制整數型別算數運算和轉換的溢位檢查內容。The checked and unchecked statements are used to control the overflow checking context for integral-type arithmetic operations and conversions.

lock 陳述式可用來取得所指定物件的互斥鎖定、執行陳述式,然後釋放鎖定。The lock statement is used to obtain the mutual-exclusion lock for a given object, execute a statement, and then release the lock.

using 陳述式可用來取得資源、執行陳述式,然後處置該資源。The using statement is used to obtain a resource, execute a statement, and then dispose of that resource.

以下是每一種語句的範例Below are examples of each kind of statement

區域變數宣告Local variable declarations

static void Main() {
   int a;
   int b = 2, c = 3;
   a = 1;
   Console.WriteLine(a + b + c);
}

本機常數宣告Local constant declaration

static void Main() {
    const float pi = 3.1415927f;
    const int r = 25;
    Console.WriteLine(pi * r * r);
}

運算陳述式Expression statement

static void Main() {
    int i;
    i = 123;                // Expression statement
    Console.WriteLine(i);   // Expression statement
    i++;                    // Expression statement
    Console.WriteLine(i);   // Expression statement
}

if 聲明if statement

static void Main(string[] args) {
    if (args.Length == 0) {
        Console.WriteLine("No arguments");
    }
    else {
        Console.WriteLine("One or more arguments");
    }
}

switch 聲明switch statement

static void Main(string[] args) {
    int n = args.Length;
    switch (n) {
        case 0:
            Console.WriteLine("No arguments");
            break;
        case 1:
            Console.WriteLine("One argument");
            break;
        default:
            Console.WriteLine("{0} arguments", n);
            break;
    }
}

while 聲明while statement

static void Main(string[] args) {
    int i = 0;
    while (i < args.Length) {
        Console.WriteLine(args[i]);
        i++;
    }
}

do 聲明do statement

static void Main() {
    string s;
    do {
        s = Console.ReadLine();
        if (s != null) Console.WriteLine(s);
    } while (s != null);
}

for 聲明for statement

static void Main(string[] args) {
    for (int i = 0; i < args.Length; i++) {
        Console.WriteLine(args[i]);
    }
}

foreach 聲明foreach statement

static void Main(string[] args) {
    foreach (string s in args) {
        Console.WriteLine(s);
    }
}

break 聲明break statement

static void Main() {
    while (true) {
        string s = Console.ReadLine();
        if (s == null) break;
        Console.WriteLine(s);
    }
}

continue 聲明continue statement

static void Main(string[] args) {
    for (int i = 0; i < args.Length; i++) {
        if (args[i].StartsWith("/")) continue;
        Console.WriteLine(args[i]);
    }
}

goto 聲明goto statement

static void Main(string[] args) {
    int i = 0;
    goto check;
    loop:
    Console.WriteLine(args[i++]);
    check:
    if (i < args.Length) goto loop;
}

return 聲明return statement

static int Add(int a, int b) {
    return a + b;
}

static void Main() {
    Console.WriteLine(Add(1, 2));
    return;
}

yield 聲明yield statement

static IEnumerable<int> Range(int from, int to) {
    for (int i = from; i < to; i++) {
        yield return i;
    }
    yield break;
}

static void Main() {
    foreach (int x in Range(-10,10)) {
        Console.WriteLine(x);
    }
}

throwtry 語句throw and try statements

static double Divide(double x, double y) {
    if (y == 0) throw new DivideByZeroException();
    return x / y;
}

static void Main(string[] args) {
    try {
        if (args.Length != 2) {
            throw new Exception("Two numbers required");
        }
        double x = double.Parse(args[0]);
        double y = double.Parse(args[1]);
        Console.WriteLine(Divide(x, y));
    }
    catch (Exception e) {
        Console.WriteLine(e.Message);
    }
    finally {
        Console.WriteLine("Good bye!");
    }
}

checkedunchecked 語句checked and unchecked statements

static void Main() {
    int i = int.MaxValue;
    checked {
        Console.WriteLine(i + 1);        // Exception
    }
    unchecked {
        Console.WriteLine(i + 1);        // Overflow
    }
}

lock 聲明lock statement

class Account
{
    decimal balance;
    public void Withdraw(decimal amount) {
        lock (this) {
            if (amount > balance) {
                throw new Exception("Insufficient funds");
            }
            balance -= amount;
        }
    }
}

using 聲明using statement

static void Main() {
    using (TextWriter w = File.CreateText("test.txt")) {
        w.WriteLine("Line one");
        w.WriteLine("Line two");
        w.WriteLine("Line three");
    }
}

類別與物件Classes and objects

*類別 _ 是 c # 類型中最基本的一種。*Classes _ are the most fundamental of C#'s types. 類別是以單一單位結合狀態 (欄位) 和動作 (方法及其他函式成員) 的資料結構。A class is a data structure that combines state (fields) and actions (methods and other function members) in a single unit. 類別提供動態建立之類別 *實例* 的定義,也稱為 *物件*A class provides a definition for dynamically created instances of the class, also known as objects. 類別支援 *繼承*** 型,也就是 *衍生類別* 可以擴充和特殊化 _ 基類 * 的機制。Classes support inheritance and polymorphism, mechanisms whereby derived classes can extend and specialize _*base classes**.

建立新類別時,是使用類別宣告來建立。New classes are created using class declarations. 類別宣告的開頭是一個標頭,此標頭會指定類別的屬性和修飾詞、類別的名稱、基底類別 (如果提供),以及類別所實作的介面。A class declaration starts with a header that specifies the attributes and modifiers of the class, the name of the class, the base class (if given), and the interfaces implemented by the class. 此標頭後面會接著類別主體,此主體是由在 {} 分隔符號之間撰寫的成員宣告清單所組成。The header is followed by the class body, which consists of a list of member declarations written between the delimiters { and }.

以下是一個名為 Point 之簡單類別的宣告:The following is a declaration of a simple class named Point:

public class Point
{
    public int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

建立類別執行個體時,是使用 new 運算子來建立,此運算子會為新執行個體配置記憶體、叫用建構函式來將執行個體初始化,然後傳回對執行個體的參考。Instances of classes are created using the new operator, which allocates memory for a new instance, invokes a constructor to initialize the instance, and returns a reference to the instance. 下列語句會建立兩個 Point 物件,並在兩個變數中儲存這些物件的參考:The following statements create two Point objects and store references to those objects in two variables:

Point p1 = new Point(0, 0);
Point p2 = new Point(10, 20);

當物件不再使用時,會自動回收物件所佔用的記憶體。The memory occupied by an object is automatically reclaimed when the object is no longer in use. 在 C# 中,既沒有必要也不可能明確地將物件解除配置。It is neither necessary nor possible to explicitly deallocate objects in C#.

成員Members

類別的成員可以是 *靜態成員 _ 或 _ 實例成員 *。The members of a class are either static members _ or _instance members**. 靜態成員隸屬於類別,而執行個體成員則隸屬於物件 (類別的執行個體)。Static members belong to classes, and instance members belong to objects (instances of classes).

下表概要說明類別可包含的成員種類。The following table provides an overview of the kinds of members a class can contain.

成員Member 說明Description
常數Constants 與類別關聯的常數值Constant values associated with the class
欄位Fields 類別的變數Variables of the class
方法Methods 類別所能執行的計算和動作Computations and actions that can be performed by the class
屬性Properties 與讀取和寫入具名的類別特性關聯的動作Actions associated with reading and writing named properties of the class
索引子Indexers 與編製陣列之類的類別執行個體關聯的動作Actions associated with indexing instances of the class like an array
事件Events 類別所能產生的通知Notifications that can be generated by the class
運算子Operators 類別所支援的轉換和運算式運算子Conversions and expression operators supported by the class
建構函式Constructors 將類別執行個體或類別本身初始化所需的動作Actions required to initialize instances of the class or the class itself
解構函式Destructors 在永久捨棄類別執行個體之前所要執行的動作Actions to perform before instances of the class are permanently discarded
類型Types 類別所宣告的巢狀型別Nested types declared by the class

協助工具選項Accessibility

類別的每個成員都有關聯的存取能力,用來控制能夠存取成員的程式文字區域。Each member of a class has an associated accessibility, which controls the regions of program text that are able to access the member. 存取能力有五種可能的形式。There are five possible forms of accessibility. 下表將摘要說明這些報表:These are summarized in the following table.

協助工具Accessibility 意義Meaning
public 存取不受限制Access not limited
protected 存取僅限於此類別或此類別所衍生的類別Access limited to this class or classes derived from this class
internal 存取僅限於此程式Access limited to this program
protected internal 存取僅限於此程式或此類別所衍生的類別Access limited to this program or classes derived from this class
private 存取僅限於此類別Access limited to this class

型別參數Type parameters

類別定義可以在類別名稱後面以角括弧括住型別參數名稱清單,來定義一組型別參數。A class definition may specify a set of type parameters by following the class name with angle brackets enclosing a list of type parameter names. 接著,就可以在類別宣告的主體中使用這些型別參數,來定義類別的成員。The type parameters can then be used in the body of the class declarations to define the members of the class. 在下列範例中,Pair 的型別參數是 TFirstTSecondIn the following example, the type parameters of Pair are TFirst and TSecond:

public class Pair<TFirst,TSecond>
{
    public TFirst First;
    public TSecond Second;
}

類別型別若宣告為會採用型別參數,即稱為「泛型類別型別」。A class type that is declared to take type parameters is called a generic class type. 結構、介面及委派型別也可以是泛型型別。Struct, interface and delegate types can also be generic.

使用泛型類別時,必須為每個型別參數提供型別參數:When the generic class is used, type arguments must be provided for each of the type parameters:

Pair<int,string> pair = new Pair<int,string> { First = 1, Second = "two" };
int i = pair.First;     // TFirst is int
string s = pair.Second; // TSecond is string

提供型別引數的泛型型別(如上所示 Pair<int,string> )稱為「已建立型別」。A generic type with type arguments provided, like Pair<int,string> above, is called a constructed type.

基底類別Base classes

類別宣告可以在類別名稱和型別參數後面加上冒號和基底類別的名稱,來指定基底類別。A class declaration may specify a base class by following the class name and type parameters with a colon and the name of the base class. 省略基底類別規格即等同於衍生自類型 objectOmitting a base class specification is the same as deriving from type object. 在下列範例中,Point3D 的基底類別是 Point,而 Point 的基底類別是 objectIn the following example, the base class of Point3D is Point, and the base class of Point is object:

public class Point
{
    public int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

public class Point3D: Point
{
    public int z;

    public Point3D(int x, int y, int z): base(x, y) {
        this.z = z;
    }
}

類別會繼承其基底類別的成員。A class inherits the members of its base class. 繼承表示類別會隱含地包含其基類的所有成員,但實例和靜態的函式除外,以及基類的析構函式。Inheritance means that a class implicitly contains all members of its base class, except for the instance and static constructors, and the destructors of the base class. 衍生類別可以在其繼承的成員中新增新的成員,但無法移除所繼承成員的定義。A derived class can add new members to those it inherits, but it cannot remove the definition of an inherited member. 在先前的範例中,Point3D 會從 Point 繼承 xy 欄位,而每個 Point3D 執行個體都會包含 xyz 這三個欄位。In the previous example, Point3D inherits the x and y fields from Point, and every Point3D instance contains three fields, x, y, and z.

在類別型別到其任何基底類別型別之間都存在著隱含轉換。An implicit conversion exists from a class type to any of its base class types. 因此,類別型別的變數可以參考該類別的執行個體,或任何衍生類別的執行個體。Therefore, a variable of a class type can reference an instance of that class or an instance of any derived class. 例如,以先前的類別宣告為例,Point 型別的變數可以參考 PointPoint3DFor example, given the previous class declarations, a variable of type Point can reference either a Point or a Point3D:

Point a = new Point(10, 20);
Point b = new Point3D(10, 20, 30);

欄位Fields

「欄位」是與類別或類別執行個體關聯的變數。A field is a variable that is associated with a class or with an instance of a class.

使用修飾詞宣告的欄位會 static 定義 靜態欄位A field declared with the static modifier defines a static field. 靜態欄位只會識別一個儲存位置。A static field identifies exactly one storage location. 不論建立多少個類別執行個體,都只會有一個靜態欄位複本。No matter how many instances of a class are created, there is only ever one copy of a static field.

未使用修飾詞宣告的欄位會 static 定義 實例欄位A field declared without the static modifier defines an instance field. 每個類別執行個體都包含一個該類別所有執行個體欄位的個別複本。Every instance of a class contains a separate copy of all the instance fields of that class.

在下列範例中,每個 Color 類別執行個體都具有 rgb 執行個體欄位的個別複本,但只有一個 BlackWhiteRedGreenBlue 靜態欄位的複本:In the following example, each instance of the Color class has a separate copy of the r, g, and b instance fields, but there is only one copy of the Black, White, Red, Green, and Blue static fields:

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue = new Color(0, 0, 255);
    private byte r, g, b;

    public Color(byte r, byte g, byte b) {
        this.r = r;
        this.g = g;
        this.b = b;
    }
}

如先前的範例所示,可以使用 readonly 修飾詞來宣告「唯讀欄位」。As shown in the previous example, read-only fields may be declared with a readonly modifier. 欄位的宣告或相同類別的函式中, readonly 只能進行指派給欄位。Assignment to a readonly field can only occur as part of the field's declaration or in a constructor in the same class.

方法Methods

*方法 _ 是一個成員,它會執行可由物件或類別執行的計算或動作。A *method _ is a member that implements a computation or action that can be performed by an object or class. *靜態方法* 是透過類別來存取。Static methods are accessed through the class. _ 實例方法* 可透過類別的實例來存取。_ Instance methods* are accessed through instances of the class.

方法的 (可能是空的 *參數 _) 清單,代表傳遞給方法的值或變數參考,以及 _ * 傳回 別 * *,指定方法所計算和傳回值的型別。Methods have a (possibly empty) list of parameters _, which represent values or variable references passed to the method, and a _return type**, which specifies the type of the value computed and returned by the method. 如果方法的傳回型別不會傳回值,則為 voidA method's return type is void if it does not return a value.

與型別相同,方法也可能有一組型別參數,而呼叫方法時,必須為這些參數指定型別引數。Like types, methods may also have a set of type parameters, for which type arguments must be specified when the method is called. 與型別不同的是,型別引數通常可以從方法呼叫的引數推斷,而不需要明確指定。Unlike types, the type arguments can often be inferred from the arguments of a method call and need not be explicitly given.

在宣告方法的類別中,方法的「簽章」必須是唯一的。The signature of a method must be unique in the class in which the method is declared. 方法的簽章是由方法的名稱、型別參數的數目以及其參數的數目、修飾詞和型別所組成。The signature of a method consists of the name of the method, the number of type parameters and the number, modifiers, and types of its parameters. 方法的簽章並不包括傳回型別。The signature of a method does not include the return type.

參數Parameters

參數是用來將值或變數參考傳遞給方法。Parameters are used to pass values or variable references to methods. 方法的參數會從叫用方法時所指定的「引數」取得其實際值。The parameters of a method get their actual values from the arguments that are specified when the method is invoked. 參數有四種:值參數、參考參數、輸出參數,以及參數陣列。There are four kinds of parameters: value parameters, reference parameters, output parameters, and parameter arrays.

「值參數」適用於傳遞輸入參數。A value parameter is used for input parameter passing. 值參數會對應至區域變數,此變數會從針對參數傳遞的引數取得其初始值。A value parameter corresponds to a local variable that gets its initial value from the argument that was passed for the parameter. 對值參數進行修改並不會影響已針對參數傳遞的引數。Modifications to a value parameter do not affect the argument that was passed for the parameter.

只要指定預設值,值參數便可以成為選用參數,如此即可省略對應的引數。Value parameters can be optional, by specifying a default value so that corresponding arguments can be omitted.

「參考參數」同時適用於傳遞輸入和輸出參數。A reference parameter is used for both input and output parameter passing. 針對參考參數傳遞的引數必須是變數,而在執行方法的期間,參考參數會代表與引數變數相同的儲存位置。The argument passed for a reference parameter must be a variable, and during execution of the method, the reference parameter represents the same storage location as the argument variable. 宣告參考參數時,是使用 ref 修飾詞來宣告。A reference parameter is declared with the ref modifier. 下列範例示範 ref 參數的用法。The following example shows the use of ref parameters.

using System;

class Test
{
    static void Swap(ref int x, ref int y) {
        int temp = x;
        x = y;
        y = temp;
    }

    static void Main() {
        int i = 1, j = 2;
        Swap(ref i, ref j);
        Console.WriteLine("{0} {1}", i, j);            // Outputs "2 1"
    }
}

「輸出參數」適用於傳遞輸出參數。An output parameter is used for output parameter passing. 輸出參數與參考參數類似,不同之處在於呼叫端所提供引數的初始值並不重要。An output parameter is similar to a reference parameter except that the initial value of the caller-provided argument is unimportant. 宣告輸出參數時,是使用 out 修飾詞來宣告。An output parameter is declared with the out modifier. 下列範例示範 out 參數的用法。The following example shows the use of out parameters.

using System;

class Test
{
    static void Divide(int x, int y, out int result, out int remainder) {
        result = x / y;
        remainder = x % y;
    }

    static void Main() {
        int res, rem;
        Divide(10, 3, out res, out rem);
        Console.WriteLine("{0} {1}", res, rem);    // Outputs "3 1"
    }
}

「參數陣列」可允許將數目不固定的引數傳遞給方法。A parameter array permits a variable number of arguments to be passed to a method. 宣告參數陣列時,是使用 params 修飾詞來宣告。A parameter array is declared with the params modifier. 只有方法的最後一個參數可以是參數陣列,而參數陣列的型別必須是單一維度陣列型別。Only the last parameter of a method can be a parameter array, and the type of a parameter array must be a single-dimensional array type. Write類別的和 WriteLine 方法 System.Console 是參數陣列使用方式的良好範例。The Write and WriteLine methods of the System.Console class are good examples of parameter array usage. 其宣告方式如下。They are declared as follows.

public class Console
{
    public static void Write(string fmt, params object[] args) {...}
    public static void WriteLine(string fmt, params object[] args) {...}
    ...
}

在使用參數陣列的方法內,參數陣列的行為與陣列型別的一般參數完全相同。Within a method that uses a parameter array, the parameter array behaves exactly like a regular parameter of an array type. 不過,在叫用含有參數陣列的方法時,可以傳遞單一的參數陣列型別引數,或是傳遞任意數目的參數陣列元素型別引數。However, in an invocation of a method with a parameter array, it is possible to pass either a single argument of the parameter array type or any number of arguments of the element type of the parameter array. 在後者的案例中,會自動建立陣列執行個體並以指定的引數將其初始化。In the latter case, an array instance is automatically created and initialized with the given arguments. 以下範例This example

Console.WriteLine("x={0} y={1} z={2}", x, y, z);

等同於撰寫下列程式碼。is equivalent to writing the following.

string s = "x={0} y={1} z={2}";
object[] args = new object[3];
args[0] = x;
args[1] = y;
args[2] = z;
Console.WriteLine(s, args);

方法主體和區域變數Method body and local variables

方法的主體會指定叫用方法時要執行的語句。A method's body specifies the statements to execute when the method is invoked.

方法主體可以宣告方法叫用專屬的變數。A method body can declare variables that are specific to the invocation of the method. 這類變數稱為「區域變數」。Such variables are called local variables. 區域變數宣告會指定型別名稱、變數名稱,還可能指定初始值。A local variable declaration specifies a type name, a variable name, and possibly an initial value. 下列範例會宣告一個初始值為零的區域變數 i,以及一個沒有初始值的區域變數 jThe following example declares a local variable i with an initial value of zero and a local variable j with no initial value.

using System;

class Squares
{
    static void Main() {
        int i = 0;
        int j;
        while (i < 10) {
            j = i * i;
            Console.WriteLine("{0} x {0} = {1}", i, j);
            i = i + 1;
        }
    }
}

C# 要求必須「明確指派」區域變數,才能取得其值。C# requires a local variable to be definitely assigned before its value can be obtained. 例如,如果先前 i 的宣告並未包含初始值,編譯器就會在 i 後續被使用時回報錯誤,因為在這些時間點並不會在程式中明確指派 iFor example, if the declaration of the previous i did not include an initial value, the compiler would report an error for the subsequent usages of i because i would not be definitely assigned at those points in the program.

方法可以使用 return 陳述式將控制權交還給其呼叫端。A method can use return statements to return control to its caller. 在傳回 void 的方法中,return 陳述式不能指定運算式。In a method returning void, return statements cannot specify an expression. 在傳回非的方法中 voidreturn 語句必須包含會計算傳回值的運算式。In a method returning non-void, return statements must include an expression that computes the return value.

靜態和執行個體方法Static and instance methods

使用修飾詞宣告的方法 static靜態方法A method declared with a static modifier is a static method. 靜態方法不會在特定的執行個體上運作,並且只能直接存取靜態成員。A static method does not operate on a specific instance and can only directly access static members.

未使用修飾詞宣告的方法 static實例方法A method declared without a static modifier is an instance method. 執行個體方法會在特定的執行個體上運作,並且既可存取靜態成員也可存取執行個體成員。An instance method operates on a specific instance and can access both static and instance members. 透過 this 可以明確存取叫用執行個體方法時所在的執行個體。The instance on which an instance method was invoked can be explicitly accessed as this. 在靜態方法中參照 this 會產生錯誤。It is an error to refer to this in a static method.

下列 Entity 類別同時含有靜態成員和執行個體成員。The following Entity class has both static and instance members.

class Entity
{
    static int nextSerialNo;
    int serialNo;

    public Entity() {
        serialNo = nextSerialNo++;
    }

    public int GetSerialNo() {
        return serialNo;
    }

    public static int GetNextSerialNo() {
        return nextSerialNo;
    }

    public static void SetNextSerialNo(int value) {
        nextSerialNo = value;
    }
}

每個 Entity 執行個體都包含一個序號 (並且可能包含一些其他這裡未顯示的資訊)。Each Entity instance contains a serial number (and presumably some other information that is not shown here). Entity 建構函式 (類似於執行個體方法) 會將具有下一個可用序號的新執行個體初始化。The Entity constructor (which is like an instance method) initializes the new instance with the next available serial number. 由於此建構函式式執行個體成員,因此它既可存取 serialNo 執行個體欄位,也可存取 nextSerialNo 靜態欄位。Because the constructor is an instance member, it is permitted to access both the serialNo instance field and the nextSerialNo static field.

GetNextSerialNoSetNextSerialNo 靜態方法可以存取 nextSerialNo 靜態欄位,但如果直接存取 serialNo 執行個體欄位,則會產生錯誤。The GetNextSerialNo and SetNextSerialNo static methods can access the nextSerialNo static field, but it would be an error for them to directly access the serialNo instance field.

下列範例示範如何使用 Entity 類別。The following example shows the use of the Entity class.

using System;

class Test
{
    static void Main() {
        Entity.SetNextSerialNo(1000);
        Entity e1 = new Entity();
        Entity e2 = new Entity();
        Console.WriteLine(e1.GetSerialNo());           // Outputs "1000"
        Console.WriteLine(e2.GetSerialNo());           // Outputs "1001"
        Console.WriteLine(Entity.GetNextSerialNo());   // Outputs "1002"
    }
}

請注意,SetNextSerialNoGetNextSerialNo 靜態方法的叫用位置是在類別上,而 GetSerialNo 執行個體方法的叫用位置則是在類別的執行個體上。Note that the SetNextSerialNo and GetNextSerialNo static methods are invoked on the class whereas the GetSerialNo instance method is invoked on instances of the class.

虛擬、覆寫及抽象方法Virtual, override, and abstract methods

當實例方法宣告包含修飾詞時 virtual ,此方法稱為 *虛擬方法 _。When an instance method declaration includes a virtual modifier, the method is said to be a *virtual method _. 當沒有任何修飾詞時,方法會被視為 virtual _ 非虛擬方法 *。When no virtual modifier is present, the method is said to be a _*non-virtual method**.

叫用虛擬方法時,該調用所發生之實例的 *執行時間類型 _ 會決定要叫用的實際方法執行。When a virtual method is invoked, the *run-time type _ of the instance for which that invocation takes place determines the actual method implementation to invoke. 在非虛擬方法調用中,實例的 _ 編譯時間類型* 是決定因素。In a nonvirtual method invocation, the _ compile-time type* of the instance is the determining factor.

在衍生類別中可以「覆寫」虛擬方法。A virtual method can be overridden in a derived class. 當實例方法宣告包含修飾詞時 override ,方法會使用相同的簽章覆寫繼承的虛擬方法。When an instance method declaration includes an override modifier, the method overrides an inherited virtual method with the same signature. 虛擬方法宣告會導入新的方法,而覆寫方法宣告則是會提供現有已繼承之虛擬方法的新實作,來將該方法特製化。Whereas a virtual method declaration introduces a new method, an override method declaration specializes an existing inherited virtual method by providing a new implementation of that method.

抽象 方法是沒有執行的虛擬方法。An abstract method is a virtual method with no implementation. 抽象方法是以修飾詞宣告 abstract ,而且只能在也宣告的類別中使用 abstractAn abstract method is declared with the abstract modifier and is permitted only in a class that is also declared abstract. 抽象方法必須在每個非抽象的衍生類別中被覆寫。An abstract method must be overridden in every non-abstract derived class.

下列範例會宣告一個抽象類別 Expression 和三個衍生的類別 ConstantVariableReferenceOperation,前者代表一個運算式樹狀架構節點,後者則會實作常數、變數參考及算數運算式的運算式樹狀架構節點。The following example declares an abstract class, Expression, which represents an expression tree node, and three derived classes, Constant, VariableReference, and Operation, which implement expression tree nodes for constants, variable references, and arithmetic operations. (這類似于,但不會與 運算式樹狀架構類型 中引入的運算式樹狀架構類型混淆) 。(This is similar to, but not to be confused with the expression tree types introduced in Expression tree types).

using System;
using System.Collections;

public abstract class Expression
{
    public abstract double Evaluate(Hashtable vars);
}

public class Constant: Expression
{
    double value;

    public Constant(double value) {
        this.value = value;
    }

    public override double Evaluate(Hashtable vars) {
        return value;
    }
}

public class VariableReference: Expression
{
    string name;

    public VariableReference(string name) {
        this.name = name;
    }

    public override double Evaluate(Hashtable vars) {
        object value = vars[name];
        if (value == null) {
            throw new Exception("Unknown variable: " + name);
        }
        return Convert.ToDouble(value);
    }
}

public class Operation: Expression
{
    Expression left;
    char op;
    Expression right;

    public Operation(Expression left, char op, Expression right) {
        this.left = left;
        this.op = op;
        this.right = right;
    }

    public override double Evaluate(Hashtable vars) {
        double x = left.Evaluate(vars);
        double y = right.Evaluate(vars);
        switch (op) {
            case '+': return x + y;
            case '-': return x - y;
            case '*': return x * y;
            case '/': return x / y;
        }
        throw new Exception("Unknown operator");
    }
}

先前的四個類別可用來建構算數運算式的模型。The previous four classes can be used to model arithmetic expressions. 例如,在使用這些類別執行個體的情況下,可以將運算式 x + 3 表示如下。For example, using instances of these classes, the expression x + 3 can be represented as follows.

Expression e = new Operation(
    new VariableReference("x"),
    '+',
    new Constant(3));

系統會叫用 Expression 執行個體的 Evaluate 方法來評估指定的運算式並產生 double 值。The Evaluate method of an Expression instance is invoked to evaluate the given expression and produce a double value. 方法會採用做為引數 a Hashtable ,其包含變數名稱 (做為專案的索引鍵) 和值 () 的專案值。The method takes as an argument a Hashtable that contains variable names (as keys of the entries) and values (as values of the entries). Evaluate方法是虛擬抽象方法,這表示非抽象衍生類別必須覆寫它以提供實際的實值。The Evaluate method is a virtual abstract method, meaning that non-abstract derived classes must override it to provide an actual implementation.

ConstantEvaluate 實作會直接傳回預存的常數。A Constant's implementation of Evaluate simply returns the stored constant. VariableReference 實值會在雜湊表中查閱變數名稱,並傳回產生的值。A VariableReference's implementation looks up the variable name in the hashtable and returns the resulting value. Operation 的實作會先評估左邊和右邊的運算元 (透過以遞迴方式叫用其 Evaluate 方法),然後才執行指定的算數運算。An Operation's implementation first evaluates the left and right operands (by recursively invoking their Evaluate methods) and then performs the given arithmetic operation.

下列程式會使用 Expression 類別來評估不同 xy 值的 x * (y + 2) 運算式。The following program uses the Expression classes to evaluate the expression x * (y + 2) for different values of x and y.

using System;
using System.Collections;

class Test
{
    static void Main() {
        Expression e = new Operation(
            new VariableReference("x"),
            '*',
            new Operation(
                new VariableReference("y"),
                '+',
                new Constant(2)
            )
        );
        Hashtable vars = new Hashtable();
        vars["x"] = 3;
        vars["y"] = 5;
        Console.WriteLine(e.Evaluate(vars));        // Outputs "21"
        vars["x"] = 1.5;
        vars["y"] = 9;
        Console.WriteLine(e.Evaluate(vars));        // Outputs "16.5"
    }
}

方法多載Method overloading

方法 * 載 _ 允許相同類別中的多個方法具有相同的名稱,但前提是它們有唯一的簽章。Method *overloading _ permits multiple methods in the same class to have the same name as long as they have unique signatures. 編譯多載方法的調用時,編譯器會使用 _ 多載 解析* 來判斷要叫用的特定方法。When compiling an invocation of an overloaded method, the compiler uses _ overload resolution* to determine the specific method to invoke. 多載解析會尋找一個與引數最相符的方法,或者,如果找不到任何一個最相符的方法,則會回報錯誤。Overload resolution finds the one method that best matches the arguments or reports an error if no single best match can be found. 下列範例示範多載解析的實際運作情況。The following example shows overload resolution in effect. Main 方法中每項叫用的註解會顯示實際叫用的方法是哪一個。The comment for each invocation in the Main method shows which method is actually invoked.

class Test
{
    static void F() {
        Console.WriteLine("F()");
    }

    static void F(object x) {
        Console.WriteLine("F(object)");
    }

    static void F(int x) {
        Console.WriteLine("F(int)");
    }

    static void F(double x) {
        Console.WriteLine("F(double)");
    }

    static void F<T>(T x) {
        Console.WriteLine("F<T>(T)");
    }

    static void F(double x, double y) {
        Console.WriteLine("F(double, double)");
    }

    static void Main() {
        F();                 // Invokes F()
        F(1);                // Invokes F(int)
        F(1.0);              // Invokes F(double)
        F("abc");            // Invokes F(object)
        F((double)1);        // Invokes F(double)
        F((object)1);        // Invokes F(object)
        F<int>(1);           // Invokes F<T>(T)
        F(1, 1);             // Invokes F(double, double)
    }
}

如範例所示,透過將引數明確轉換成確切的參數型別和 (或) 明確提供型別引數,即一律可以選取特定的方法。As shown by the example, a particular method can always be selected by explicitly casting the arguments to the exact parameter types and/or explicitly supplying type arguments.

其他函式成員Other function members

包含可執行程式碼的成員統稱為類別的「函式成員」。Members that contain executable code are collectively known as the function members of a class. 上節中所述的方法是主要的函式成員類型。The preceding section describes methods, which are the primary kind of function members. 本節說明 c # 支援的其他類型函數成員:函式、屬性、索引子、事件、運算子和析構函數。This section describes the other kinds of function members supported by C#: constructors, properties, indexers, events, operators, and destructors.

下列程式碼顯示名為的泛型類別 List<T> ,它會實可成長物件清單。The following code shows a generic class called List<T>, which implements a growable list of objects. 此類別包含數個最常見的函式成員類型。The class contains several examples of the most common kinds of function members.

public class List<T> {
    // Constant...
    const int defaultCapacity = 4;

    // Fields...
    T[] items;
    int count;

    // Constructors...
    public List(int capacity = defaultCapacity) {
        items = new T[capacity];
    }

    // Properties...
    public int Count {
        get { return count; }
    }
    public int Capacity {
        get {
            return items.Length;
        }
        set {
            if (value < count) value = count;
            if (value != items.Length) {
                T[] newItems = new T[value];
                Array.Copy(items, 0, newItems, 0, count);
                items = newItems;
            }
        }
    }

    // Indexer...
    public T this[int index] {
        get {
            return items[index];
        }
        set {
            items[index] = value;
            OnChanged();
        }
    }

    // Methods...
    public void Add(T item) {
        if (count == Capacity) Capacity = count * 2;
        items[count] = item;
        count++;
        OnChanged();
    }
    protected virtual void OnChanged() {
        if (Changed != null) Changed(this, EventArgs.Empty);
    }
    public override bool Equals(object other) {
        return Equals(this, other as List<T>);
    }
    static bool Equals(List<T> a, List<T> b) {
        if (a == null) return b == null;
        if (b == null || a.count != b.count) return false;
        for (int i = 0; i < a.count; i++) {
            if (!object.Equals(a.items[i], b.items[i])) {
                return false;
            }
        }
        return true;
    }

    // Event...
    public event EventHandler Changed;

    // Operators...
    public static bool operator ==(List<T> a, List<T> b) {
        return Equals(a, b);
    }
    public static bool operator !=(List<T> a, List<T> b) {
        return !Equals(a, b);
    }
}

建構函式Constructors

C# 同時支援執行個體建構函式和靜態建構函式。C# supports both instance and static constructors. *實例 的函式 _ 是一個成員,它會執行初始化類別實例所需的動作。An *instance constructor _ is a member that implements the actions required to initialize an instance of a class. _ 靜態 函式 * 是在第一次載入類別本身時,可執行初始化類別本身所需動作的成員。A _ static constructor* is a member that implements the actions required to initialize a class itself when it is first loaded.

建構函式的宣告方式與方法類似,但不含傳回型別且名稱會與包含它的類別相同。A constructor is declared like a method with no return type and the same name as the containing class. 如果函式宣告包含修飾詞 static ,就會宣告靜態的函式。If a constructor declaration includes a static modifier, it declares a static constructor. 否則,所宣告的會是執行個體建構函式。Otherwise, it declares an instance constructor.

可以多載實例的函式。Instance constructors can be overloaded. 例如,List<T> 類別會宣告兩個執行個體建構函式,一個沒有任何參數,另一個會採用 int 參數。For example, the List<T> class declares two instance constructors, one with no parameters and one that takes an int parameter. 叫用執行個體建構函式時,是使用 new 運算子來叫用。Instance constructors are invoked using the new operator. 下列語句會使用類別的每個函式來配置兩個 List<string> 實例 ListThe following statements allocate two List<string> instances using each of the constructors of the List class.

List<string> list1 = new List<string>();
List<string> list2 = new List<string>(10);

與其他成員不同,類別並不會繼承執行個體建構函式,而且除了類別中實際宣告的執行個體建構函式以外,類別即不會再有任何執行個體建構函式。Unlike other members, instance constructors are not inherited, and a class has no instance constructors other than those actually declared in the class. 如果沒有為類別提供任何執行個體建構函式,則會自動提供一個沒有任何參數的空建構函式。If no instance constructor is supplied for a class, then an empty one with no parameters is automatically provided.

屬性Properties

*屬性 _ 是欄位的自然延伸。*Properties _ are a natural extension of fields. 兩者都是具有關聯型別的具名成員,並且用來存取欄位和屬性的語法是相同的。Both are named members with associated types, and the syntax for accessing fields and properties is the same. 不過,與欄位不同的是,屬性並不會指示儲存位置。However, unlike fields, properties do not denote storage locations. 相反地,屬性具有 _ 存取 子 *,可指定讀取或寫入其值時要執行的語句。Instead, properties have _ accessors* that specify the statements to be executed when their values are read or written.

屬性的宣告方式與欄位類似,不同之處在于宣告的結尾是 get 存取子和(或) set 在分隔符號之間寫入的存取子, { } 而不是以分號結尾。A property is declared like a field, except that the declaration ends with a get accessor and/or a set accessor written between the delimiters { and } instead of ending in a semicolon. 同時具有 get 存取子和存取子的屬性 set讀寫屬性 _、只有一個存取子的屬性 get 是 _唯讀屬性*,而只有一個存取子的屬性 set 為 _ *僅限寫入屬性* *。A property that has both a get accessor and a set accessor is a read-write property _, a property that has only a get accessor is a _read-only property*, and a property that has only a set accessor is a _*write-only property**.

get存取子對應至具有屬性類型之傳回值的無參數方法。A get accessor corresponds to a parameterless method with a return value of the property type. 除了做為指派的目標之外,在運算式中參考屬性時,會叫用 get 屬性的存取子來計算屬性的值。Except as the target of an assignment, when a property is referenced in an expression, the get accessor of the property is invoked to compute the value of the property.

存取子會 set 與名為且沒有傳回型別的單一參數的方法對應 valueA set accessor corresponds to a method with a single parameter named value and no return type. 當屬性被視為指派的目標或作為或的運算元時 ++ --set 就會使用提供新值的引數來叫用存取子。When a property is referenced as the target of an assignment or as the operand of ++ or --, the set accessor is invoked with an argument that provides the new value.

List<T> 類別會宣告 CountCapacity 這兩個屬性,它們分別是唯讀屬性和讀寫屬性。The List<T> class declares two properties, Count and Capacity, which are read-only and read-write, respectively. 以下是這些屬性的用法範例。The following is an example of use of these properties.

List<string> names = new List<string>();
names.Capacity = 100;            // Invokes set accessor
int i = names.Count;             // Invokes get accessor
int j = names.Capacity;          // Invokes get accessor

與欄位和方法類似,C# 也同時支援執行個體屬性和靜態屬性。Similar to fields and methods, C# supports both instance properties and static properties. 靜態屬性是以修飾詞宣告 static ,而實例屬性則是在沒有它的情況下宣告。Static properties are declared with the static modifier, and instance properties are declared without it.

屬性的存取子可以是虛擬的。The accessor(s) of a property can be virtual. 當屬性宣告包含 virtualabstractoverride 修飾詞時,會套用至該屬性的存取子。When a property declaration includes a virtual, abstract, or override modifier, it applies to the accessor(s) of the property.

索引子Indexers

「索引子」是可讓物件以和陣列相同的方式進行索引編製的成員。An indexer is a member that enables objects to be indexed in the same way as an array. 索引子的宣告方式與屬性類似,不同之處在於成員的名稱是 this,後面接著在 [] 分隔符號之間撰寫的參數清單。An indexer is declared like a property except that the name of the member is this followed by a parameter list written between the delimiters [ and ]. 索引子的存取子中會提供參數。The parameters are available in the accessor(s) of the indexer. 與屬性類似,索引子可以是讀寫、唯讀及唯寫的,而索引子的存取子可以是虛擬的。Similar to properties, indexers can be read-write, read-only, and write-only, and the accessor(s) of an indexer can be virtual.

List 類別會宣告一個採用 int 參數的單一讀寫索引子。The List class declares a single read-write indexer that takes an int parameter. 此索引子使得系統能夠以 int 值編製 List 執行個體的索引。The indexer makes it possible to index List instances with int values. 例如:For example

List<string> names = new List<string>();
names.Add("Liz");
names.Add("Martha");
names.Add("Beth");
for (int i = 0; i < names.Count; i++) {
    string s = names[i];
    names[i] = s.ToUpper();
}

索引子可被多載,這意謂著類別可以宣告多個索引子,只要其參數的號碼或型別不同即可。Indexers can be overloaded, meaning that a class can declare multiple indexers as long as the number or types of their parameters differ.

事件Events

「事件」是可讓類別或物件提供通知的成員。An event is a member that enables a class or object to provide notifications. 事件的宣告方式與欄位類似,不同之處在于宣告 event 會包含關鍵字,而類型必須是委派類型。An event is declared like a field except that the declaration includes an event keyword and the type must be a delegate type.

在宣告事件成員的類別內,事件的行為與委派型別的欄位相同 (前提是該事件不是抽象事件且未宣告存取子)。Within a class that declares an event member, the event behaves just like a field of a delegate type (provided the event is not abstract and does not declare accessors). 欄位會儲存對委派項目的參考,該委派項目代表已新增到事件中的事件處理常式。The field stores a reference to a delegate that represents the event handlers that have been added to the event. 如果沒有任何事件控制碼存在,則欄位為 nullIf no event handles are present, the field is null.

List<T> 類別會宣告一個名為 Changed 的單一事件成員,此成員會指出新項目已新增到清單中。The List<T> class declares a single event member called Changed, which indicates that a new item has been added to the list. Changed 事件是由 OnChanged 虛擬方法引發,它會先檢查事件是否 null (表示沒有任何處理程式存在) 。The Changed event is raised by the OnChanged virtual method, which first checks whether the event is null (meaning that no handlers are present). 引發事件的概念完全等同於叫用該事件所代表的委派項目,因此,就引發事件而言,並沒有任何特殊的語言建構。The notion of raising an event is precisely equivalent to invoking the delegate represented by the event—thus, there are no special language constructs for raising events.

用戶端是透過「事件處理常式」來對事件進行反應。Clients react to events through event handlers. 附加事件處理常式時,是使用 += 運算子,移除時,則是使用 -= 運算子。Event handlers are attached using the += operator and removed using the -= operator. 下列範例會將事件處理常式附加到 List<string>Changed 事件。The following example attaches an event handler to the Changed event of a List<string>.

using System;

class Test
{
    static int changeCount;

    static void ListChanged(object sender, EventArgs e) {
        changeCount++;
    }

    static void Main() {
        List<string> names = new List<string>();
        names.Changed += new EventHandler(ListChanged);
        names.Add("Liz");
        names.Add("Martha");
        names.Add("Beth");
        Console.WriteLine(changeCount);        // Outputs "3"
    }
}

針對需要控制事件之基礎儲存的進階案例,事件宣告可以明確提供 addremove 存取子,這有些類似於屬性的 set 存取子。For advanced scenarios where control of the underlying storage of an event is desired, an event declaration can explicitly provide add and remove accessors, which are somewhat similar to the set accessor of a property.

運算子Operators

「運算子」是定義將特定運算式運算子套用到類別執行個體之意義的成員。An operator is a member that defines the meaning of applying a particular expression operator to instances of a class. 可定義的運算子有三種:一元運算子、二元運算子及轉換運算子。Three kinds of operators can be defined: unary operators, binary operators, and conversion operators. 所有運算子都必須宣告為 publicstaticAll operators must be declared as public and static.

List<T> 類別會宣告 operator==operator!= 這兩個運算子,藉此賦予將這些運算子套用到 List 執行個體的運算式新意義。The List<T> class declares two operators, operator== and operator!=, and thus gives new meaning to expressions that apply those operators to List instances. 具體而言,運算子會定義兩個 List<T> 實例是否相等,以使用其方法來比較每個包含的物件 EqualsSpecifically, the operators define equality of two List<T> instances as comparing each of the contained objects using their Equals methods. 下列範例會使用 == 運算子來比較兩個 List<int> 執行個體。The following example uses the == operator to compare two List<int> instances.

using System;

class Test
{
    static void Main() {
        List<int> a = new List<int>();
        a.Add(1);
        a.Add(2);
        List<int> b = new List<int>();
        b.Add(1);
        b.Add(2);
        Console.WriteLine(a == b);        // Outputs "True"
        b.Add(3);
        Console.WriteLine(a == b);        // Outputs "False"
    }
}

第一個 Console.WriteLine 會輸出 True,因為兩個清單所包含物件的數目相同、值相同且順序相同。The first Console.WriteLine outputs True because the two lists contain the same number of objects with the same values in the same order. 如果 List<T> 並未定義 operator==,則第一個 Console.WriteLine 所輸出的會是 False,因為 ab 參考不同的 List<int> 執行個體。Had List<T> not defined operator==, the first Console.WriteLine would have output False because a and b reference different List<int> instances.

解構函式Destructors

式」是一種成員,它會執行銷毀類別實例所需的動作。A destructor is a member that implements the actions required to destruct an instance of a class. 析構函數不能有參數,它們不能有存取範圍修飾詞,而且無法明確地叫用。Destructors cannot have parameters, they cannot have accessibility modifiers, and they cannot be invoked explicitly. 在垃圾收集期間,會自動叫用實例的函式。The destructor for an instance is invoked automatically during garbage collection.

垃圾收集行程允許使用寬緯度來決定何時收集物件和執行析構函數。The garbage collector is allowed wide latitude in deciding when to collect objects and run destructors. 具體來說,函式調用的時間不具決定性,而且可以在任何執行緒上執行析構函數。Specifically, the timing of destructor invocations is not deterministic, and destructors may be executed on any thread. 基於這些原因和其他原因,類別應該只有在沒有其他可行的解決方案時,才會執行析構函數。For these and other reasons, classes should implement destructors only when no other solutions are feasible.

using 陳述式提供較佳的物件解構方法。The using statement provides a better approach to object destruction.

結構Structs

和類別一樣,結構 是可包含資料成員和函式成員的資料結構,但不同於類別,結構是實值型別,不需要堆積配置。Like classes, structs are data structures that can contain data members and function members, but unlike classes, structs are value types and do not require heap allocation. 結構型別的變數直接儲存結構的資料,而類別型別的變數則儲存動態配置物件的參考。A variable of a struct type directly stores the data of the struct, whereas a variable of a class type stores a reference to a dynamically allocated object. 結構型別不支援使用者指定的繼承,且所有結構型別都隱含地繼承自 object 型別。Struct types do not support user-specified inheritance, and all struct types implicitly inherit from type object.

結構特別適用於含有實值語意的小型資料結構。Structs are particularly useful for small data structures that have value semantics. 複數、座標系統中的點或字典中的索引鍵/值組都是結構的良好範例。Complex numbers, points in a coordinate system, or key-value pairs in a dictionary are all good examples of structs. 針對小型資料結構使用結構而不使用類別,在應用程式執行的記憶體配置數目上有很大的差別。The use of structs rather than classes for small data structures can make a large difference in the number of memory allocations an application performs. 比方說,下列程式會建立並初始化 100 個點的陣列。For example, the following program creates and initializes an array of 100 points. 使用 Point 做為類別,會具現化 101 個不同的物件 — 一個代表陣列,剩下的每個代表 100 個元素。With Point implemented as a class, 101 separate objects are instantiated—one for the array and one each for the 100 elements.

class Point
{
    public int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

class Test
{
    static void Main() {
        Point[] points = new Point[100];
        for (int i = 0; i < 100; i++) points[i] = new Point(i, i);
    }
}

替代方式是建立 Point 結構。An alternative is to make Point a struct.

struct Point
{
    public int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

現在,只有一個物件會具現化 — 代表陣列的物件 — 而 Point 執行個體會以內嵌方式儲存在陣列中。Now, only one object is instantiated—the one for the array—and the Point instances are stored in-line in the array.

結構建構函式使用 new 運算子叫用,但並不代表會配置記憶體。Struct constructors are invoked with the new operator, but that does not imply that memory is being allocated. 結構建構函式只會傳回結構值本身 (通常是在堆疊上的暫存位置),然後再視需要複製此值,而不是動態配置一個物件並傳回該物件的參考。Instead of dynamically allocating an object and returning a reference to it, a struct constructor simply returns the struct value itself (typically in a temporary location on the stack), and this value is then copied as necessary.

使用類別時,這兩種變數可以參考相同的物件,因此對其中一個變數進行的作業可能會影響另一個變數參考的物件。With classes, it is possible for two variables to reference the same object and thus possible for operations on one variable to affect the object referenced by the other variable. 使用結構時,變數各有自己的資料複本,因此在某一個變數上進行的作業不可能會影響其他變數。With structs, the variables each have their own copy of the data, and it is not possible for operations on one to affect the other. 例如,下列程式碼片段所產生的輸出取決於是否 Point 為類別或結構。For example, the output produced by the following code fragment depends on whether Point is a class or a struct.

Point a = new Point(10, 10);
Point b = a;
a.x = 20;
Console.WriteLine(b.x);

如果 Point 是類別,則輸出為, 20 a 而且會 b 參考相同的物件。If Point is a class, the output is 20 because a and b reference the same object. 如果 Point 是結構,則輸出是 10 因為的指派會 a b 建立值的複本,而這個複本不會受到後續指派的影響 a.xIf Point is a struct, the output is 10 because the assignment of a to b creates a copy of the value, and this copy is unaffected by the subsequent assignment to a.x.

前一個範例會反白顯示結構的兩個限制。The previous example highlights two of the limitations of structs. 首先,複製整個結構通常較複製物件參考沒有效率,因此,結構的指派和實值參數傳遞會比參考型別耗用更多資源。First, copying an entire struct is typically less efficient than copying an object reference, so assignment and value parameter passing can be more expensive with structs than with reference types. 再者,除了 refout 參數外,不可能建立結構的參考,因此在許多情況下無法使用它們。Second, except for ref and out parameters, it is not possible to create references to structs, which rules out their usage in a number of situations.

陣列Arrays

*Array _ 是一種資料結構,其中包含一些透過計算索引存取的變數。An *array _ is a data structure that contains a number of variables that are accessed through computed indices. 陣列中包含的變數(也稱為陣列的 *元素* )全都是相同的類型,而這個型別稱為數組的 _ *元素類型**。The variables contained in an array, also called the elements of the array, are all of the same type, and this type is called the _ element type* of the array.

陣列型別是參考型別,而陣列變數的宣告只是預留空間給陣列執行個體的參考。Array types are reference types, and the declaration of an array variable simply sets aside space for a reference to an array instance. 實際的陣列實例是在執行時間使用運算子動態建立 newActual array instances are created dynamically at run-time using the new operator. 作業 new 會指定新陣列實例的 長度 ,然後針對實例的存留期進行修正。The new operation specifies the length of the new array instance, which is then fixed for the lifetime of the instance. 陣列元素的索引範圍在 0Length - 1 之間。The indices of the elements of an array range from 0 to Length - 1. new 運算子會自動將陣列的元素初始化為其預設值,例如,針對所有數值型別,此值為零,而針對所有參考型別,此值為 nullThe new operator automatically initializes the elements of an array to their default value, which, for example, is zero for all numeric types and null for all reference types.

下列範例會建立 int 元素的陣列、初始化陣列,並印出陣列的內容。The following example creates an array of int elements, initializes the array, and prints out the contents of the array.

using System;

class Test
{
    static void Main() {
        int[] a = new int[10];
        for (int i = 0; i < a.Length; i++) {
            a[i] = i * i;
        }
        for (int i = 0; i < a.Length; i++) {
            Console.WriteLine("a[{0}] = {1}", i, a[i]);
        }
    }
}

這個範例會建立並操作 * 一 維陣列 _。This example creates and operates on a *single-dimensional array _. C # 也支援 *多維度陣列*C# also supports multi-dimensional arrays. 陣列類型的維度數目(也稱為陣列類型的 _ 順 ***)是一個加上在陣列類型的方括弧之間所寫入的逗號數目。The number of dimensions of an array type, also known as the _ rank* of the array type, is one plus the number of commas written between the square brackets of the array type. 下列範例會配置一維的二維、二維和三維陣列。The following example allocates a one-dimensional, a two-dimensional, and a three-dimensional array.

int[] a1 = new int[10];
int[,] a2 = new int[10, 5];
int[,,] a3 = new int[10, 5, 2];

a1 陣列包含 10 個元素、a2陣列包含 50 (10 × 5) 個元素,a3 陣列包含 100 (10 × 5 × 2) 個元素。The a1 array contains 10 elements, the a2 array contains 50 (10 × 5) elements, and the a3 array contains 100 (10 × 5 × 2) elements.

陣列的元素型別可以是任一型別,包括陣列型別。The element type of an array can be any type, including an array type. 包含陣列型別之元素的陣列有時稱為 不規則陣列,因為元素陣列的長度不需完全相同。An array with elements of an array type is sometimes called a jagged array because the lengths of the element arrays do not all have to be the same. 下列範例會配置一個 int 型別的陣列:The following example allocates an array of arrays of int:

int[][] a = new int[3][];
a[0] = new int[10];
a[1] = new int[5];
a[2] = new int[20];

第一行建立包含三個元素的陣列,每個元素的型別均為 int[],每個元素的初始值均為 nullThe first line creates an array with three elements, each of type int[] and each with an initial value of null. 接下來的幾行則使用不同長度的個別陣列執行個體的參考初始化三個元素。The subsequent lines then initialize the three elements with references to individual array instances of varying lengths.

new運算子允許使用 陣列初始化 運算式來指定陣列元素的初始值,也就是在分隔符號和之間寫入的運算式清單 { }The new operator permits the initial values of the array elements to be specified using an array initializer, which is a list of expressions written between the delimiters { and }. 下列範例使用三個元素配置並初始化 int[]The following example allocates and initializes an int[] with three elements.

int[] a = new int[] {1, 2, 3};

請注意,陣列的長度是從和之間的運算式數目推斷 { 而來 }Note that the length of the array is inferred from the number of expressions between { and }. 本機變數與欄位宣告可以進一步縮短,就不需要重新敘述陣列型別。Local variable and field declarations can be shortened further such that the array type does not have to be restated.

int[] a = {1, 2, 3};

先前的兩個範例等同於下列範例:Both of the previous examples are equivalent to the following:

int[] t = new int[3];
t[0] = 1;
t[1] = 2;
t[2] = 3;
int[] a = t;

介面Interfaces

「介面」定義可由類別和結構實作的合約。An interface defines a contract that can be implemented by classes and structs. 介面可以包含方法、屬性、事件和索引子。An interface can contain methods, properties, events, and indexers. 介面不提供它所定義之成員的實作 (它只會指定必須由類別提供的成員或實作介面的結構)。An interface does not provide implementations of the members it defines—it merely specifies the members that must be supplied by classes or structs that implement the interface.

介面可以採用「多重繼承」。Interfaces may employ multiple inheritance. 在下列範例中,介面 IComboBox 同時繼承自 ITextBoxIListBoxIn the following example, the interface IComboBox inherits from both ITextBox and IListBox.

interface IControl
{
    void Paint();
}

interface ITextBox: IControl
{
    void SetText(string text);
}

interface IListBox: IControl
{
    void SetItems(string[] items);
}

interface IComboBox: ITextBox, IListBox {}

類別和結構可以實作多個介面。Classes and structs can implement multiple interfaces. 在下列範例中,類別 EditBox 可以實作 IControlIDataBound 兩者。In the following example, the class EditBox implements both IControl and IDataBound.

interface IDataBound
{
    void Bind(Binder b);
}

public class EditBox: IControl, IDataBound
{
    public void Paint() {...}
    public void Bind(Binder b) {...}
}

當類別或結構實作特定介面時,可以將該類別或結構的執行個體隱含地轉換為該介面型別。When a class or struct implements a particular interface, instances of that class or struct can be implicitly converted to that interface type. 例如:For example

EditBox editBox = new EditBox();
IControl control = editBox;
IDataBound dataBound = editBox;

在實作特定介面的執行個體無法確知的情況下,可以使用動態型別轉換。In cases where an instance is not statically known to implement a particular interface, dynamic type casts can be used. 例如,下列語句會使用動態型別轉換來取得物件和介面的實作為 IControl IDataBoundFor example, the following statements use dynamic type casts to obtain an object's IControl and IDataBound interface implementations. 因為物件的實際類型為,所以 EditBox 轉換會成功。Because the actual type of the object is EditBox, the casts succeed.

object obj = new EditBox();
IControl control = (IControl)obj;
IDataBound dataBound = (IDataBound)obj;

在先前的 EditBox 類別中,介面的 Paint 方法 IControl 和介面中的 Bind 方法 IDataBound 是使用成員來執行 publicIn the previous EditBox class, the Paint method from the IControl interface and the Bind method from the IDataBound interface are implemented using public members. C # 也支援 明確介面成員 實作為,類別或結構可以避免建立成員 publicC# also supports explicit interface member implementations, using which the class or struct can avoid making the members public. 明確介面成員實作是使用介面成員完整名稱來撰寫。An explicit interface member implementation is written using the fully qualified interface member name. 例如,EditBox 類別可以使用明確介面成員實作來實作 IControl.PaintIDataBound.Bind 方法,如下所示。For example, the EditBox class could implement the IControl.Paint and IDataBound.Bind methods using explicit interface member implementations as follows.

public class EditBox: IControl, IDataBound
{
    void IControl.Paint() {...}
    void IDataBound.Bind(Binder b) {...}
}

明確介面成員只能透過介面型別來存取。Explicit interface members can only be accessed via the interface type. 例如,您 IControl.Paint EditBox 只能先將 EditBox 參考轉換為 IControl 介面型別,才能叫用前一個類別所提供的實作為。For example, the implementation of IControl.Paint provided by the previous EditBox class can only be invoked by first converting the EditBox reference to the IControl interface type.

EditBox editBox = new EditBox();
editBox.Paint();                        // Error, no such method
IControl control = editBox;
control.Paint();                        // Ok

列舉Enums

「列舉型別」是含一組具名常數的相異實值型別。An enum type is a distinct value type with a set of named constants. 下列範例會宣告並使用名為的列舉類型,並使用 Color 三個常數值、、 Red GreenBlueThe following example declares and uses an enum type named Color with three constant values, Red, Green, and Blue.

using System;

enum Color
{
    Red,
    Green,
    Blue
}

class Test
{
    static void PrintColor(Color color) {
        switch (color) {
            case Color.Red:
                Console.WriteLine("Red");
                break;
            case Color.Green:
                Console.WriteLine("Green");
                break;
            case Color.Blue:
                Console.WriteLine("Blue");
                break;
            default:
                Console.WriteLine("Unknown color");
                break;
        }
    }

    static void Main() {
        Color c = Color.Red;
        PrintColor(c);
        PrintColor(Color.Blue);
    }
}

每個列舉類型都有對應的整數型別,稱為列舉型別的 基礎型 別。Each enum type has a corresponding integral type called the underlying type of the enum type. 未明確宣告基礎型別的列舉型別具有的基礎型別 intAn enum type that does not explicitly declare an underlying type has an underlying type of int. 列舉類型的儲存格式和可能的值範圍取決於其基礎類型。An enum type's storage format and range of possible values are determined by its underlying type. 列舉型別所能採用的一組值不受其列舉成員的限制。The set of values that an enum type can take on is not limited by its enum members. 尤其是列舉的基礎類型的任何值都可以轉換成列舉型別,而且是該列舉型別的相異有效值。In particular, any value of the underlying type of an enum can be cast to the enum type and is a distinct valid value of that enum type.

下列範例會宣告以的基礎型別命名的列舉型別 Alignment sbyteThe following example declares an enum type named Alignment with an underlying type of sbyte.

enum Alignment: sbyte
{
    Left = -1,
    Center = 0,
    Right = 1
}

如上一個範例所示,列舉成員宣告可以包含指定成員值的常數運算式。As shown by the previous example, an enum member declaration can include a constant expression that specifies the value of the member. 每個列舉成員的常數值必須在列舉的基礎類型範圍內。The constant value for each enum member must be in the range of the underlying type of the enum. 當列舉成員宣告未明確指定值時,如果成員是列舉型別中的第一個成員) 或以文字方式加上的列舉成員值加1,就會將值指定為零 (。When an enum member declaration does not explicitly specify a value, the member is given the value zero (if it is the first member in the enum type) or the value of the textually preceding enum member plus one.

您可以使用類型轉換將列舉值轉換成整數值,反之亦然。Enum values can be converted to integral values and vice versa using type casts. 例如:For example

int i = (int)Color.Blue;        // int i = 2;
Color c = (Color)2;             // Color c = Color.Blue;

任何列舉型別的預設值都是轉換成列舉型別的整數值零。The default value of any enum type is the integral value zero converted to the enum type. 在變數自動初始化為預設值的情況下,這是提供給列舉類型之變數的值。In cases where variables are automatically initialized to a default value, this is the value given to variables of enum types. 為了讓列舉型別的預設值更容易使用,常值會 0 隱含地轉換成任何列舉型別。In order for the default value of an enum type to be easily available, the literal 0 implicitly converts to any enum type. 因此,允許以下的情況。Thus, the following is permitted.

Color c = 0;

委派Delegates

「委派型別」代表對方法的參考,其中含有特定參數清單與傳回型別。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 similar to the concept of function pointers found in some other languages, but unlike function pointers, delegates are object-oriented and type-safe.

下列範例會宣告並使用名為 Function 的委派型別。The following example declares and uses a delegate type named Function.

using System;

delegate double Function(double x);

class Multiplier
{
    double factor;

    public Multiplier(double factor) {
        this.factor = factor;
    }

    public double Multiply(double x) {
        return x * factor;
    }
}

class Test
{
    static double Square(double x) {
        return x * x;
    }

    static double[] Apply(double[] a, Function f) {
        double[] result = new double[a.Length];
        for (int i = 0; i < a.Length; i++) result[i] = f(a[i]);
        return result;
    }

    static void Main() {
        double[] a = {0.0, 0.5, 1.0};
        double[] squares = Apply(a, Square);
        double[] sines = Apply(a, Math.Sin);
        Multiplier m = new Multiplier(2.0);
        double[] doubles =  Apply(a, m.Multiply);
    }
}

Function 委派型別的執行個體可以參考任何採用 double 引數並傳回 double 值的方法。An instance of the Function delegate type can reference any method that takes a double argument and returns a double value. Apply方法會將指定的套用 Function 至的元素 double[] ,並傳回 double[] 包含結果的。The Apply method applies a given Function to the elements of a double[], returning a double[] with the results. Main 方法中,是使用 Apply 將三個不同的函式套用到 double[]In the Main method, Apply is used to apply three different functions to a double[].

委派可以參考靜態方法 (例如上一個範例中的 SquareMath.Sin),或是參考執行個體方法 (例如上一個範例中的 m.Multiply)。A delegate can reference either a static method (such as Square or Math.Sin in the previous example) or an instance method (such as m.Multiply in the previous example). 參考執行個體方法的委派也會參考特定的物件,而且透過委派來叫用執行個體方法時,該物件就會變成叫用中的 thisA delegate that references an instance method also references a particular object, and when the instance method is invoked through the delegate, that object becomes this in the invocation.

您也可以使用匿名函式來建立委派,這些函式是動態建立的「內嵌方法」。Delegates can also be created using anonymous functions, which are "inline methods" that are created on the fly. 匿名函式可以看見周圍方法的區域變數。Anonymous functions can see the local variables of the surrounding methods. 因此,您可以更輕鬆地撰寫上述乘數範例,而不需要使用 Multiplier 類別:Thus, the multiplier example above can be written more easily without using a Multiplier class:

double[] doubles =  Apply(a, (double x) => x * 2.0);

委派有一個有趣且實用的屬性,就是它並不知道或並不在乎所參考方法的類別;唯一重要的是所參考的方法具有與委派相同的參數和傳回型別。An interesting and useful property of a delegate is that it does not know or care about the class of the method it references; all that matters is that the referenced method has the same parameters and return type as the delegate.

屬性Attributes

C# 程式中的型別、成員和其他實體支援控制其某方面行為的修飾詞。Types, members, and other entities in a C# program support modifiers that control certain aspects of their behavior. 例如,方法的協助工具是使用 publicprotectedinternalprivate 修飾詞控制。For example, the accessibility of a method is controlled using the public, protected, internal, and private modifiers. C# 將此能力一般化,宣告式資訊的使用者定義型別才能附加至程式實體,並在執行階段擷取。C# generalizes this capability such that user-defined types of declarative information can be attached to program entities and retrieved at run-time. 程式是透過定義和使用 屬性 指定這項額外的宣告式資訊。Programs specify this additional declarative information by defining and using attributes.

下列範例宣告的 HelpAttribute 屬性可置於程式實體,以提供其相關文件的連結。The following example declares a HelpAttribute attribute that can be placed on program entities to provide links to their associated documentation.

using System;

public class HelpAttribute: Attribute
{
    string url;
    string topic;

    public HelpAttribute(string url) {
        this.url = url;
    }

    public string Url {
        get { return url; }
    }

    public string Topic {
        get { return topic; }
        set { topic = value; }
    }
}

所有屬性類別都是衍生自 System.Attribute .NET Framework 所提供的基類。All attribute classes derive from the System.Attribute base class provided by the .NET Framework. 在相關聯的宣告之前,於方括弧中提供屬性的名稱 (及任何引數) 即可套用屬性。Attributes can be applied by giving their name, along with any arguments, inside square brackets just before the associated declaration. 如果屬性的名稱結束,則在 Attribute 參考屬性時可以省略該部分的名稱。If an attribute's name ends in Attribute, that part of the name can be omitted when the attribute is referenced. 例如,HelpAttribute 屬性可以下列方式使用。For example, the HelpAttribute attribute can be used as follows.

[Help("http://msdn.microsoft.com/.../MyClass.htm")]
public class Widget
{
    [Help("http://msdn.microsoft.com/.../MyClass.htm", Topic = "Display")]
    public void Display(string text) {}
}

這個範例會將加入 HelpAttributeWidget 類別,並將另一個附加 HelpAttributeDisplay 類別中的方法。This example attaches a HelpAttribute to the Widget class and another HelpAttribute to the Display method in the class. 屬性類別的公用建構函式控制將屬性附加至程式實體時必須提供的資訊。The public constructors of an attribute class control the information that must be provided when the attribute is attached to a program entity. 透過參考屬性類別的公用讀寫屬性可提供其他資訊 (例如先前對 Topic 的參考 )。Additional information can be provided by referencing public read-write properties of the attribute class (such as the reference to the Topic property previously).

下列範例顯示如何在執行時間使用反映來抓取指定程式實體的屬性資訊。The following example shows how attribute information for a given program entity can be retrieved at run-time using reflection.

using System;
using System.Reflection;

class Test
{
    static void ShowHelp(MemberInfo member) {
        HelpAttribute a = Attribute.GetCustomAttribute(member,
            typeof(HelpAttribute)) as HelpAttribute;
        if (a == null) {
            Console.WriteLine("No help for {0}", member);
        }
        else {
            Console.WriteLine("Help for {0}:", member);
            Console.WriteLine("  Url={0}, Topic={1}", a.Url, a.Topic);
        }
    }

    static void Main() {
        ShowHelp(typeof(Widget));
        ShowHelp(typeof(Widget).GetMethod("Display"));
    }
}

透過反射要求特定的屬性時,會以程式來源中提供的資訊叫用屬性類別的建構函式,並傳回產生的屬性執行個體。When a particular attribute is requested through reflection, the constructor for the attribute class is invoked with the information provided in the program source, and the resulting attribute instance is returned. 如果是透過屬性提供其他資訊,傳回屬性執行個體之前,這些屬性會設為指定的值。If additional information was provided through properties, those properties are set to the given values before the attribute instance is returned.