内置引用类型(C# 引用)Built-in reference types (C# reference)

C# 具有多个内置引用类型。C# has a number of built-in reference types. 这些类型包含的关键字或运算符是 .NET 库中的类型的同义词。They have keywords or operators that are synonyms for a type in the .NET library.

对象类型The object type

object 类型是 System.Object 在 .NET 中的别名。The object type is an alias for System.Object in .NET. 在 C# 的统一类型系统中,所有类型(预定义类型、用户定义类型、引用类型和值类型)都是直接或间接从 System.Object 继承的。In the unified type system of C#, all types, predefined and user-defined, reference types and value types, inherit directly or indirectly from System.Object. 可以将任何类型的值赋给 object 类型的变量。You can assign values of any type to variables of type object. 可以使用文本 null 将任何 object 变量赋值给其默认值。Any object variable can be assigned to its default value using the literal null. 将值类型的变量转换为对象的过程称为 装箱When a variable of a value type is converted to object, it is said to be boxed . object 类型的变量转换为值类型的过程称为取消装箱 。When a variable of type object is converted to a value type, it is said to be unboxed . 有关详细信息,请参阅装箱和取消装箱For more information, see Boxing and Unboxing.

字符串类型The string type

string 类型表示零个或多个 Unicode 字符的序列。The string type represents a sequence of zero or more Unicode characters. stringSystem.String 在 .NET 中的别名。string is an alias for System.String in .NET.

尽管 string 为引用类型,但是定义相等运算符 ==!= 是为了比较 string 对象(而不是引用)的值。Although string is a reference type, the equality operators == and != are defined to compare the values of string objects, not references. 这使得对字符串相等性的测试更为直观。This makes testing for string equality more intuitive. 例如: 。For example:

string a = "hello";
string b = "h";
// Append to contents of 'b'
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine(object.ReferenceEquals(a, b));

此时将显示“True”,然后显示“False”,因为字符串的内容是相等的,但 ab 并不指代同一字符串实例。This displays "True" and then "False" because the content of the strings are equivalent, but a and b do not refer to the same string instance.

+ 运算符连接字符串:The + operator concatenates strings:

string a = "good " + "morning";

这将创建包含“good morning”的字符串对象。This creates a string object that contains "good morning".

字符串是不可变的 ,即:字符串对象在创建后,尽管从语法上看似乎可以更改其内容,但事实上并不可行。Strings are immutable --the contents of a string object cannot be changed after the object is created, although the syntax makes it appear as if you can do this. 例如,编写此代码时,编译器实际上会创建一个新的字符串对象来保存新的字符序列,且该新对象将赋给 bFor example, when you write this code, the compiler actually creates a new string object to hold the new sequence of characters, and that new object is assigned to b. 已为 b 分配的内存(当它包含字符串“h”时)可用于垃圾回收。The memory that had been allocated for b (when it contained the string "h") is then eligible for garbage collection.

string b = "h";
b += "ello";

[] 运算符可用于只读访问字符串的个别字符。The [] operator can be used for readonly access to individual characters of a string. 有效索引于 0 开始,且必须小于字符串的长度:Valid index values start at 0 and must be less than the length of the string:

string str = "test";
char x = str[2];  // x = 's';

同样,[] 运算符也可用于循环访问字符串中的每个字符:In similar fashion, the [] operator can also be used for iterating over each character in a string:

string str = "test";

for (int i = 0; i < str.Length; i++)
{
  Console.Write(str[i] + " ");
}
// Output: t e s t

字符串文本属于 string 类型且可以两种形式编写(带引号和仅 @ 带引号)。String literals are of type string and can be written in two forms, quoted and @-quoted. 带引号字符串括在双引号 (") 内。Quoted string literals are enclosed in double quotation marks ("):

"good morning"  // a string literal

字符串文本可包含任何字符文本。String literals can contain any character literal. 包括转义序列。Escape sequences are included. 下面的示例使用转义序列 \\ 表示反斜杠,使用 \u0066 表示字母 f,以及使用 \n 表示换行符。The following example uses escape sequence \\ for backslash, \u0066 for the letter f, and \n for newline.

string a = "\\\u0066\n F";
Console.WriteLine(a);
// Output:
// \f
//  F

备注

转义码 \udddd(其中 dddd 是一个四位数字)表示 Unicode 字符 U+ddddThe escape code \udddd (where dddd is a four-digit number) represents the Unicode character U+dddd. 另外,还可识别八位 Unicode 转义码:\UddddddddEight-digit Unicode escape codes are also recognized: \Udddddddd.

逐字字符串文本@ 开头,并且也括在双引号内。Verbatim string literals start with @ and are also enclosed in double quotation marks. 例如: 。For example:

@"good morning"  // a string literal

逐字字符串的优点是不处理转义序列,这样就可轻松编写完全限定的 Windows 文件名等 :The advantage of verbatim strings is that escape sequences are not processed, which makes it easy to write, for example, a fully qualified Windows file name:

@"c:\Docs\Source\a.txt"  // rather than "c:\\Docs\\Source\\a.txt"

若要在 @-quoted 字符串中包含双引号,双倍添加即可:To include a double quotation mark in an @-quoted string, double it:

@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.

委托类型The delegate type

委托类型的声明与方法签名相似。The declaration of a delegate type is similar to a method signature. 它有一个返回值和任意数目任意类型的参数:It has a return value and any number of parameters of any type:

public delegate void MessageDelegate(string message);
public delegate int AnotherDelegate(MyType m, long num);

在 .NET 中,System.ActionSystem.Func 类型为许多常见委托提供泛型定义。In .NET, System.Action and System.Func types provide generic definitions for many common delegates. 可能不需要定义新的自定义委托类型。You likely don't need to define new custom delegate types. 相反,可以创建提供的泛型类型的实例化。Instead, you can create instantiations of the provided generic types.

delegate 是一种可用于封装命名方法或匿名方法的引用类型。A delegate is a reference type that can be used to encapsulate a named or an anonymous method. 委托类似于 C++ 中的函数指针;但是,委托是类型安全和可靠的。Delegates are similar to function pointers in C++; however, delegates are type-safe and secure. 有关委托的应用,请参阅委托泛型委托For applications of delegates, see Delegates and Generic Delegates. 委托是事件的基础。Delegates are the basis for Events. 通过将委托与命名方法或匿名方法关联,可以实例化委托。A delegate can be instantiated by associating it either with a named or anonymous method.

必须使用具有兼容返回类型和输入参数的方法或 lambda 表达式实例化委托。The delegate must be instantiated with a method or lambda expression that has a compatible return type and input parameters. 有关方法签名中允许的差异程度的详细信息,请参阅委托中的变体For more information on the degree of variance that is allowed in the method signature, see Variance in Delegates. 为了与匿名方法一起使用,委托和与之关联的代码必须一起声明。For use with anonymous methods, the delegate and the code to be associated with it are declared together.

动态类型The dynamic type

dynamic 类型表示变量的使用和对其成员的引用绕过编译时类型检查。The dynamic type indicates that use of the variable and references to its members bypass compile-time type checking. 改为在运行时解析这些操作。Instead, these operations are resolved at run time. dynamic 类型简化了对 COM API(例如 Office Automation API)、动态 API(例如 IronPython 库)和 HTML 文档对象模型 (DOM) 的访问。The dynamic type simplifies access to COM APIs such as the Office Automation APIs, to dynamic APIs such as IronPython libraries, and to the HTML Document Object Model (DOM).

在大多数情况下,dynamic 类型与 object 类型的行为类似。Type dynamic behaves like type object in most circumstances. 具体而言,任何非 Null 表达式都可以转换为 dynamic 类型。In particular, any non-null expression can be converted to the dynamic type. dynamic 类型与 object 的不同之处在于,编译器不会对包含类型 dynamic 的表达式的操作进行解析或类型检查。The dynamic type differs from object in that operations that contain expressions of type dynamic are not resolved or type checked by the compiler. 编译器将有关该操作信息打包在一起,之后这些信息会用于在运行时评估操作。The compiler packages together information about the operation, and that information is later used to evaluate the operation at run time. 在此过程中,dynamic 类型的变量会编译为 object 类型的变量。As part of the process, variables of type dynamic are compiled into variables of type object. 因此,dynamic 类型只在编译时存在,在运行时则不存在。Therefore, type dynamic exists only at compile time, not at run time.

下面的示例将 dynamic 类型的变量与 object 类型的变量进行对比。The following example contrasts a variable of type dynamic to a variable of type object. 若要在编译时验证每个变量的类型,请将鼠标指针放在 WriteLine 语句中的 dynobj 上。To verify the type of each variable at compile time, place the mouse pointer over dyn or obj in the WriteLine statements. 请将下面的代码复制到可以使用 IntelliSense 的编辑器中。Copy the following code into an editor where IntelliSense is available. IntelliSense 对 dyn 显示“dynamic” ,对 obj 显示“object” 。IntelliSense shows dynamic for dyn and object for obj.

class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;

        // Rest the mouse pointer over dyn and obj to see their
        // types at compile time.
        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

WriteLine 语句显示 dynobj 的运行时类型。The WriteLine statements display the run-time types of dyn and obj. 此时,两者的类型均为整数。At that point, both have the same type, integer. 将生成以下输出:The following output is produced:

System.Int32
System.Int32

若要查看编译时 dynobj 之间的区别,请在前面示例的声明和 WriteLine 语句之间添加下列两行。To see the difference between dyn and obj at compile time, add the following two lines between the declarations and the WriteLine statements in the previous example.

dyn = dyn + 3;
obj = obj + 3;

尝试在表达式 obj + 3 中添加整数和对象时,将报告编译器错误。A compiler error is reported for the attempted addition of an integer and an object in expression obj + 3. 但是,对于 dyn + 3,不会报告任何错误。However, no error is reported for dyn + 3. 在编译时不会检查包含 dyn 的表达式,原因是 dyn 的类型为 dynamicThe expression that contains dyn is not checked at compile time because the type of dyn is dynamic.

下面的示例在多个声明中使用 dynamicThe following example uses dynamic in several declarations. Main 方法也将编译时类型检查与运行时类型检查进行了对比。The Main method also contrasts compile-time type checking with run-time type checking.

using System;

namespace DynamicExamples
{
    class Program
    {
        static void Main(string[] args)
        {
            ExampleClass ec = new ExampleClass();
            Console.WriteLine(ec.exampleMethod(10));
            Console.WriteLine(ec.exampleMethod("value"));

            // The following line causes a compiler error because exampleMethod
            // takes only one argument.
            //Console.WriteLine(ec.exampleMethod(10, 4));

            dynamic dynamic_ec = new ExampleClass();
            Console.WriteLine(dynamic_ec.exampleMethod(10));

            // Because dynamic_ec is dynamic, the following call to exampleMethod
            // with two arguments does not produce an error at compile time.
            // However, it does cause a run-time error.
            //Console.WriteLine(dynamic_ec.exampleMethod(10, 4));
        }
    }

    class ExampleClass
    {
        static dynamic field;
        dynamic prop { get; set; }

        public dynamic exampleMethod(dynamic d)
        {
            dynamic local = "Local variable";
            int two = 2;

            if (d is int)
            {
                return local;
            }
            else
            {
                return two;
            }
        }
    }
}
// Results:
// Local variable
// 2
// Local variable

另请参阅See also