常规类型系统Common Type System

通用类型系统定义了如何在公共语言运行时中声明、使用和管理类型,同时也是运行时跨语言集成支持的一个重要组成部分。The common type system defines how types are declared, used, and managed in the common language runtime, and is also an important part of the runtime's support for cross-language integration. 常规类型系统执行以下功能:The common type system performs the following functions:

  • 建立一个支持跨语言集成、类型安全和高性能代码执行的框架。Establishes a framework that helps enable cross-language integration, type safety, and high-performance code execution.

  • 提供一个支持完整实现多种编程语言的面向对象的模型。Provides an object-oriented model that supports the complete implementation of many programming languages.

  • 定义各语言必须遵守的规则,有助于确保用不同语言编写的对象能够交互作用。Defines rules that languages must follow, which helps ensure that objects written in different languages can interact with each other.

  • 提供包含应用程序开发中使用的基元数据类型(如BooleanByteCharInt32UInt64)的库。Provides a library that contains the primitive data types (such as Boolean, Byte, Char, Int32, and UInt64) used in application development.

本主题包含以下各节:This topic contains the following sections:

.NET 中的类型Types in .NET

.NET 中的所有类型不是值类型就是引用类型。All types in .NET are either value types or reference types.

值类型是使用对象实际值来表示对象的数据类型。Value types are data types whose objects are represented by the object's actual value. 如果向一个变量分配值类型的实例,则该变量将被赋以该值的全新副本。If an instance of a value type is assigned to a variable, that variable is given a fresh copy of the value.

引用类型是使用对对象实际值的引用(类似于指针)来表示对象的数据类型。Reference types are data types whose objects are represented by a reference (similar to a pointer) to the object's actual value. 如果为某个变量分配一个引用类型,则该变量将引用(或指向)原始值。If a reference type is assigned to a variable, that variable references (points to) the original value. 不创建任何副本。No copy is made.

.NET 中的通用类型系统支持以下五种类别的类型:The common type system in .NET supports the following five categories of types:

Classes

类是可以直接从另一个类派生以及从 System.Object 隐式派生的引用类型。A class is a reference type that can be derived directly from another class and that is derived implicitly from System.Object. 类定义对象(它是该类的实例)可以执行的操作(方法、事件或属性)和该对象包含的数据(字段)。The class defines the operations that an object (which is an instance of the class) can perform (methods, events, or properties) and the data that the object contains (fields). 尽管类通常同时包含定义和实现(与接口不同,例如,接口只包含定义而不包含实现),但它也可以有一个或多个没有实现的成员。Although a class generally includes both definition and implementation (unlike interfaces, for example, which contain only definition without implementation), it can have one or more members that have no implementation.

下表介绍了类可以具有的一些特征。The following table describes some of the characteristics that a class may have. 支持运行时的每种语言都提供了一种方法,来指示类或类成员具有其中的一种或多种特征。Each language that supports the runtime provides a way to indicate that a class or class member has one or more of these characteristics. 但是,针对 .NET 的各个编程语言不能使所有这些特征都可用。However, individual programming languages that target .NET may not make all these characteristics available.

特征Characteristic 说明Description
sealedsealed 指定不能从此类型派生出另一个类。Specifies that another class cannot be derived from this type.
实现implements 指出该类通过提供接口成员的实现,使用一个或多个接口。Indicates that the class uses one or more interfaces by providing implementations of interface members.
abstractabstract 指出无法实例化类。Indicates that the class cannot be instantiated. 若要使用它,必须由其派生出另一个类。To use it, you must derive another class from it.
继承inherits 指出可以在指定了基类的任何地方使用类的实例。Indicates that instances of the class can be used anywhere the base class is specified. 从基类继承的派生类可以使用基类提供的任何公共成员的实现,派生类也可以用自己的实现重写这些公共成员的实现。A derived class that inherits from a base class can use the implementation of any public members provided by the base class, or the derived class can override the implementation of the public members with its own implementation.
exported 或 not exportedexported or not exported 指出某个类在定义它的程序集之外是否可见。Indicates whether a class is visible outside the assembly in which it is defined. 此特征仅适用于顶级类,不适用于嵌套类。This characteristic applies only to top-level classes and not to nested classes.

备注

类也可以嵌套在父类或结构中。A class can also be nested in a parent class or structure. 嵌套类也有成员特征。Nested classes also have member characteristics. 有关详细信息,请参阅嵌套类型For more information, see Nested Types.

没有实现的类成员是抽象成员。Class members that have no implementation are abstract members. 有一个或更多抽象成员的类其本身也是抽象的;不可以创建它的新实例。A class that has one or more abstract members is itself abstract; new instances of it cannot be created. 以运行时为目标的某些语言允许将类标记为抽象类,即使其成员都不是抽象成员也是如此。Some languages that target the runtime let you mark a class as abstract even if none of its members are abstract. 当要封装一组派生类可在适当时候继承或重写的基本功能时,可以使用抽象类。You can use an abstract class when you want to encapsulate a basic set of functionality that derived classes can inherit or override when appropriate. 非抽象的类称为具体类。Classes that are not abstract are referred to as concrete classes.

类可以实现任意数目的接口,但是它除了 System.Object(所有类都可以隐式从它继承)之外,只能从一个基类继承。A class can implement any number of interfaces, but it can inherit from only one base class in addition to System.Object, from which all classes inherit implicitly. 所有的类都必须至少有一个构造函数,该函数初始化此类的新实例。All classes must have at least one constructor, which initializes new instances of the class. 如果没有显式定义构造函数,大多数编译器将自动提供一个无参数构造函数。If you do not explicitly define a constructor, most compilers will automatically provide a parameterless constructor.

结构Structures

结构是隐式从 System.ValueType 派生的值类型,后者则是从 System.Object 派生的。A structure is a value type that derives implicitly from System.ValueType, which in turn is derived from System.Object. 对于表示内存要求很小的值以及将值作为按值参数传递给具有强类型参数的方法,结构很有用。A structure is very useful for representing values whose memory requirements are small, and for passing values as by-value parameters to methods that have strongly typed parameters. 在 .NET 中,所有基元数据类型(BooleanByteCharDateTimeDecimalDoubleInt16Int32Int64SByteSingleUInt16UInt32UInt64)都定义为结构。In .NET, all primitive data types (Boolean, Byte, Char, DateTime, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, and UInt64) are defined as structures.

像类一样,结构同时定义数据(结构的字段)和可以对该数据执行的操作(结构的方法)。Like classes, structures define both data (the fields of the structure) and the operations that can be performed on that data (the methods of the structure). 这意味着可以对结构调用方法,包括在 System.ObjectSystem.ValueType 类上定义的虚方法以及在值类型自身上定义的任意方法。This means that you can call methods on structures, including the virtual methods defined on the System.Object and System.ValueType classes, and any methods defined on the value type itself. 换句话说,结构可以具有字段、属性和事件以及静态和非静态方法。In other words, structures can have fields, properties, and events, as well as static and nonstatic methods. 您可以创建结构的实例,将它们作为参数传递,将它们存储为局部变量,或将它们存储在另一值类型或引用类型的字段中。You can create instances of structures, pass them as parameters, store them as local variables, or store them in a field of another value type or reference type. 结构也可以实现接口。Structures can also implement interfaces.

值类型与类在一些方面也是不同的。Value types also differ from classes in several respects. 首先,尽管它们都从 System.ValueType 隐式继承,但是它们不能从任何类型直接继承。First, although they implicitly inherit from System.ValueType, they cannot directly inherit from any type. 同样,所有值类型都是密封的,这意味着不能从它们派生出其他类型。Similarly, all value types are sealed, which means that no other type can be derived from them. 它们也不需要构造函数。They also do not require constructors.

对于每一种值类型,公共语言运行时都提供一种相应的已装箱类型,它是与值类型有着相同状态和行为的类。For each value type, the common language runtime supplies a corresponding boxed type, which is a class that has the same state and behavior as the value type. 将值类型的实例传递到接受 System.Object 类型的参数的方法时,会将它装箱。An instance of a value type is boxed when it is passed to a method that accepts a parameter of type System.Object. 当控件从接受值类型作为传引用参数的方法调用返回时,会将它拆箱(即它从类实例重新转换回值类型的实例)。It is unboxed (that is, converted from an instance of a class back to an instance of a value type) when control returns from a method call that accepts a value type as a by-reference parameter. 当需要已装箱的类型时,某些语言要求使用特殊的语法;而另外一些语言会在需要时自动使用已装箱的类型。Some languages require that you use special syntax when the boxed type is required; others automatically use the boxed type when it is needed. 在定义值类型时,需要同时定义已装箱和未装箱的类型。When you define a value type, you are defining both the boxed and the unboxed type.

枚举Enumerations

枚举 (enum) 是一种值类型,该值类型直接从 System.Enum 继承并为基础基元类型的值提供替代名称。An enumeration (enum) is a value type that inherits directly from System.Enum and that supplies alternate names for the values of an underlying primitive type. 枚举类型具有一个名称、一个必须为某个内置带符号或不带符号的整数类型的基础类型(如 ByteInt32UInt64)以及一组字段。An enumeration type has a name, an underlying type that must be one of the built-in signed or unsigned integer types (such as Byte, Int32, or UInt64), and a set of fields. 字段是静态文本字段,其中的每一个字段都表示常数。The fields are static literal fields, each of which represents a constant. 同一个值可以分配给多个字段。The same value can be assigned to multiple fields. 出现这种情况时,必须将其中某个值标记为主要枚举值,以便进行反射和字符串转换。When this occurs, you must mark one of the values as the primary enumeration value for reflection and string conversion.

可以将基础类型的值分配给枚举,反之亦然(运行时不要求强制转换)。You can assign a value of the underlying type to an enumeration and vice versa (no cast is required by the runtime). 可以创建枚举的实例,并调用 System.Enum 的方法以及在枚举的基础类型上定义的任何方法。You can create an instance of an enumeration and call the methods of System.Enum, as well as any methods defined on the enumeration's underlying type. 但是,某些语言可能不允许在要求基础类型的实例时将枚举作为参数传递(反之亦然)。However, some languages might not let you pass an enumeration as a parameter when an instance of the underlying type is required (or vice versa).

对于枚举还有以下附加限制:The following additional restrictions apply to enumerations:

  • 它们不能定义自己的方法。They cannot define their own methods.

  • 它们不能实现接口。They cannot implement interfaces.

  • 它们不能定义属性或事件。They cannot define properties or events.

  • 枚举不能是泛型,除非它嵌套在泛型类型中,才能是泛型。They cannot be generic, unless they are generic only because they are nested within a generic type. 也就是说,枚举不能有自己的类型参数。That is, an enumeration cannot have type parameters of its own.

    备注

    用 Visual Basic、C# 和 C++ 创建的嵌套类型(包括枚举)包含所有封闭泛型类型的类型参数,因此即使这些嵌套类型没有自己的类型参数,它们也是泛型的。Nested types (including enumerations) created with Visual Basic, C#, and C++ include the type parameters of all enclosing generic types, and are therefore generic even if they do not have type parameters of their own. 有关更多信息,请参见 Type.MakeGenericType 参考主题中的“嵌套类型”。For more information, see "Nested Types" in the Type.MakeGenericType reference topic.

FlagsAttribute 特性表示一种特殊的枚举,称为位域。The FlagsAttribute attribute denotes a special kind of enumeration called a bit field. 运行时本身不区分传统枚举与位域,但您的语言可能会区分二者。The runtime itself does not distinguish between traditional enumerations and bit fields, but your language might do so. 当区分二者的时候,可以对位域(而不是枚举)使用位操作符以产生未命名的值。When this distinction is made, bitwise operators can be used on bit fields, but not on enumerations, to generate unnamed values. 枚举一般用于列出唯一的元素,如一周的各天、国家/地区名称,等等。Enumerations are generally used for lists of unique elements, such as days of the week, country or region names, and so on. 位域一般用于列出可能联合发生的质量或数量,比如 Red And Big And FastBit fields are generally used for lists of qualities or quantities that might occur in combination, such as Red And Big And Fast.

下面的示例说明如何使用位域和传统枚举。The following example shows how to use both bit fields and traditional enumerations.

using System;
using System.Collections.Generic;

// A traditional enumeration of some root vegetables.
public enum SomeRootVegetables
{
    HorseRadish,
    Radish,
    Turnip
}

// A bit field or flag enumeration of harvesting seasons.
[Flags]
public enum Seasons
{
    None = 0,
    Summer = 1,
    Autumn = 2,
    Winter = 4,
    Spring = 8,
    All = Summer | Autumn | Winter | Spring
}

public class Example
{
   public static void Main()
   {
       // Hash table of when vegetables are available.
       Dictionary<SomeRootVegetables, Seasons> AvailableIn = new Dictionary<SomeRootVegetables, Seasons>();

       AvailableIn[SomeRootVegetables.HorseRadish] = Seasons.All;
       AvailableIn[SomeRootVegetables.Radish] = Seasons.Spring;
       AvailableIn[SomeRootVegetables.Turnip] = Seasons.Spring | 
            Seasons.Autumn;

       // Array of the seasons, using the enumeration.
       Seasons[] theSeasons = new Seasons[] { Seasons.Summer, Seasons.Autumn, 
            Seasons.Winter, Seasons.Spring };

       // Print information of what vegetables are available each season.
       foreach (Seasons season in theSeasons)
       {
          Console.Write(String.Format(
              "The following root vegetables are harvested in {0}:\n", 
              season.ToString("G")));
          foreach (KeyValuePair<SomeRootVegetables, Seasons> item in AvailableIn)
          {
             // A bitwise comparison.
             if (((Seasons)item.Value & season) > 0)
                 Console.Write(String.Format("  {0:G}\n", 
                      (SomeRootVegetables)item.Key));
          }
       }
   }
}
// The example displays the following output:
//    The following root vegetables are harvested in Summer:
//      HorseRadish
//    The following root vegetables are harvested in Autumn:
//      Turnip
//      HorseRadish
//    The following root vegetables are harvested in Winter:
//      HorseRadish
//    The following root vegetables are harvested in Spring:
//      Turnip
//      Radish
//      HorseRadish
Imports System.Collections.Generic

' A traditional enumeration of some root vegetables.
Public Enum SomeRootVegetables
   HorseRadish
   Radish
   Turnip
End Enum 

' A bit field or flag enumeration of harvesting seasons.
<Flags()> Public Enum Seasons
   None = 0
   Summer = 1
   Autumn = 2
   Winter = 4
   Spring = 8
   All = Summer Or Autumn Or Winter Or Spring
End Enum 

' Entry point.
Public Class Example
   Public Shared Sub Main()
      ' Hash table of when vegetables are available.
      Dim AvailableIn As New Dictionary(Of SomeRootVegetables, Seasons)()
        
      AvailableIn(SomeRootVegetables.HorseRadish) = Seasons.All
      AvailableIn(SomeRootVegetables.Radish) = Seasons.Spring
      AvailableIn(SomeRootVegetables.Turnip) = Seasons.Spring Or _
                                               Seasons.Autumn
        
      ' Array of the seasons, using the enumeration.
      Dim theSeasons() As Seasons = {Seasons.Summer, Seasons.Autumn, _
                                     Seasons.Winter, Seasons.Spring}
        
      ' Print information of what vegetables are available each season.
      For Each season As Seasons In theSeasons
         Console.WriteLine(String.Format( _
              "The following root vegetables are harvested in {0}:", _
              season.ToString("G")))
         For Each item As KeyValuePair(Of SomeRootVegetables, Seasons) In AvailableIn
            ' A bitwise comparison.
            If(CType(item.Value, Seasons) And season) > 0 Then
               Console.WriteLine("  " + _
                     CType(item.Key, SomeRootVegetables).ToString("G"))
            End If
         Next
      Next
   End Sub 
End Class 
' The example displays the following output:
'    The following root vegetables are harvested in Summer:
'      HorseRadish
'    The following root vegetables are harvested in Autumn:
'      Turnip
'      HorseRadish
'    The following root vegetables are harvested in Winter:
'      HorseRadish
'    The following root vegetables are harvested in Spring:
'      Turnip
'      Radish
'      HorseRadish

接口Interfaces

接口定义用于指定“可以执行”关系或“具有”关系的协定。An interface defines a contract that specifies a "can do" relationship or a "has a" relationship. 接口通常用于实现某种功能,如比较和排序(IComparableIComparable<T> 接口)、测试相等性(IEquatable<T> 接口)或枚举集合中的项(IEnumerableIEnumerable<T> 接口)。Interfaces are often used to implement functionality, such as comparing and sorting (the IComparable and IComparable<T> interfaces), testing for equality (the IEquatable<T> interface), or enumerating items in a collection (the IEnumerable and IEnumerable<T> interfaces). 接口可具有属性、方法和事件,所有这些都是抽象成员;也就是说,虽然接口定义这些成员及其签名,但每个接口成员的功能由实现该接口的类型定义。Interfaces can have properties, methods, and events, all of which are abstract members; that is, although the interface defines the members and their signatures, it leaves it to the type that implements the interface to define the functionality of each interface member. 这意味着实现接口的任何类或结构都必须为该接口中声明的抽象成员提供定义。This means that any class or structure that implements an interface must supply definitions for the abstract members declared in the interface. 接口也可以要求任何实现类或结构实现一个或多个其他接口。An interface can require any implementing class or structure to also implement one or more other interfaces.

对接口有以下限制:The following restrictions apply to interfaces:

  • 接口可以用任何可访问性来声明,但接口成员必须全都具有公共可访问性。An interface can be declared with any accessibility, but interface members must all have public accessibility.

  • 接口不能定义构造函数。Interfaces cannot define constructors.

  • 接口不能定义字段。Interfaces cannot define fields.

  • 接口只能定义实例成员。Interfaces can define only instance members. 它们不能定义静态成员。They cannot define static members.

每种语言都必须提供映射规则,将实现映射到需要该成员的接口,因为多个接口可以使用同一个签名声明成员,而这些成员可以分别具有单独的实现。Each language must provide rules for mapping an implementation to the interface that requires the member, because more than one interface can declare a member with the same signature, and these members can have separate implementations.

委托Delegates

委托是用途类似于 C++ 中的函数指针的引用类型。Delegates are reference types that serve a purpose similar to that of function pointers in C++. 它们用于 .NET 中的事件处理程序和回调函数。They are used for event handlers and callback functions in .NET. 与函数指针不同,委托是安全、可验证和类型安全的。Unlike function pointers, delegates are secure, verifiable, and type safe. 委托类型可以表示任何具有兼容签名的实例方法或静态方法。A delegate type can represent any instance method or static method that has a compatible signature.

如果委托参数的类型的限制性强于方法参数的类型,则该委托的参数与该方法的相应参数兼容,因为这可保证传递给委托的参数可以安全地传递给方法。A parameter of a delegate is compatible with the corresponding parameter of a method if the type of the delegate parameter is more restrictive than the type of the method parameter, because this guarantees that an argument passed to the delegate can be passed safely to the method.

同样,如果方法的返回类型的限制性强于委托的返回类型,则该委托的返回类型与该方法的返回类型兼容,因为这可保证方法的返回值可以安全地强制转换为委托的返回类型。Similarly, the return type of a delegate is compatible with the return type of a method if the return type of the method is more restrictive than the return type of the delegate, because this guarantees that the return value of the method can be cast safely to the return type of the delegate.

例如,具有类型为 IEnumerable 的参数和 Object 返回类型的委托可以表示具有类型为 Object 的参数和类型为 IEnumerable 的返回值的方法。For example, a delegate that has a parameter of type IEnumerable and a return type of Object can represent a method that has a parameter of type Object and a return value of type IEnumerable. 有关更多信息及代码示例,请参见 Delegate.CreateDelegate(Type, Object, MethodInfo)For more information and example code, see Delegate.CreateDelegate(Type, Object, MethodInfo).

委托一般绑定到它表示的方法。A delegate is said to be bound to the method it represents. 除了绑定到方法之外,委托还可以绑定到对象。In addition to being bound to the method, a delegate can be bound to an object. 该对象表示方法的第一个参数,每次调用委托时将该对象传递给方法。The object represents the first parameter of the method, and is passed to the method every time the delegate is invoked. 如果方法是实例方法,则将绑定的对象作为隐式 this 参数(在 Visual Basic 中为 Me)传递;如果方法为静态方法,则将该对象作为方法的第一个形参传递,并且委托签名必须匹配其余参数。If the method is an instance method, the bound object is passed as the implicit this parameter (Me in Visual Basic); if the method is static, the object is passed as the first formal parameter of the method, and the delegate signature must match the remaining parameters. 有关更多信息及代码示例,请参见 System.DelegateFor more information and example code, see System.Delegate.

所有委托从 System.MulticastDelegate(继承自 System.Delegate)继承。All delegates inherit from System.MulticastDelegate, which inherits from System.Delegate. C#、Visual Basic 和 C++ 语言不允许从这些类型继承,The C#, Visual Basic, and C++ languages do not allow inheritance from these types. 而是提供了用于声明委托的关键字。Instead, they provide keywords for declaring delegates.

由于委托从 MulticastDelegate 继承,因此委托具有一个调用列表,其中列出了委托表示的方法,在调用委托时将执行该列表中的方法。Because delegates inherit from MulticastDelegate, a delegate has an invocation list, which is a list of methods that the delegate represents and that are executed when the delegate is invoked. 列表中的所有方法接收调用委托时提供的自变量。All methods in the list receive the arguments supplied when the delegate is invoked.

备注

没有为在调用列表中包含多个方法的委托(即使委托具有返回类型)定义返回值。The return value is not defined for a delegate that has more than one method in its invocation list, even if the delegate has a return type.

在许多情况下(例如使用回调方法),一个委托只表示一个方法,而您需要做的就是创建委托并调用它。In many cases, such as with callback methods, a delegate represents only one method, and the only actions you have to take are creating the delegate and invoking it.

对于表示多个方法的委托,.NET 提供了 DelegateMulticastDelegate 委托类的方法,以支持如下操作:将方法添加到委托的调用列表(Delegate.Combine 方法)、移除方法(Delegate.Remove 方法)、获取调用列表(Delegate.GetInvocationList 方法)。For delegates that represent multiple methods, .NET provides methods of the Delegate and MulticastDelegate delegate classes to support operations such as adding a method to a delegate's invocation list (the Delegate.Combine method), removing a method (the Delegate.Remove method), and getting the invocation list (the Delegate.GetInvocationList method).

备注

不需要将这些方法用于 C#、C++ 和 Visual Basic 中的事件处理程序委托,因为这些语言为添加和移除事件处理程序提供了语法。It is not necessary to use these methods for event-handler delegates in C#, C++, and Visual Basic, because these languages provide syntax for adding and removing event handlers.

类型定义Type Definitions

类型定义包括以下内容:A type definition includes the following:

  • 对该类型定义的任何特性。Any attributes defined on the type.

  • 类型的可访问性(可见性)。The type's accessibility (visibility).

  • 类型的名称。The type's name.

  • 类型的基本类型。The type's base type.

  • 该类型实现的任何接口。Any interfaces implemented by the type.

  • 每个类型的成员的定义。Definitions for each of the type's members.

特性Attributes

特性提供附加的用户定义元数据。Attributes provide additional user-defined metadata. 它们通常用于在程序集中存储有关类型的附加信息,或在设计时或运行时环境中用于修改类型成员的行为。Most commonly, they are used to store additional information about a type in its assembly, or to modify the behavior of a type member in either the design-time or run-time environment.

特性本身是从 System.Attribute 继承的类。Attributes are themselves classes that inherit from System.Attribute. 每种支持使用特性的语言都有自己的语法,用于将特性应用到某个语言元素。Languages that support the use of attributes each have their own syntax for applying attributes to a language element. 特性可应用到几乎任意语言元素;特性可以应用到的特定元素由应用到该特性类的 AttributeUsageAttribute 定义。Attributes can be applied to almost any language element; the specific elements to which an attribute can be applied are defined by the AttributeUsageAttribute that is applied to that attribute class.

类型可访问性Type Accessibility

所有类型都有一个修饰符,控制从其他类型对它们的可访问性。All types have a modifier that governs their accessibility from other types. 下表说明了运行时所支持的类型可访问性。The following table describes the type accessibilities supported by the runtime.

可访问性Accessibility 说明Description
publicpublic 所有程序集都可以访问此类型。The type is accessible by all assemblies.
程序集 (assembly)assembly 只能在其程序集内访问此类型。The type is accessible only from within its assembly.

嵌套类型的可访问性依赖于它的可访问域,该域是由已声明的成员可访问性和直接包含类型的可访问域这二者共同确定的。The accessibility of a nested type depends on its accessibility domain, which is determined by both the declared accessibility of the member and the accessibility domain of the immediately containing type. 但是,嵌套类型的可访问域不能超出包含类型的可访问域。However, the accessibility domain of a nested type cannot exceed that of the containing type.

在程序 M 的类型 T 中,声明的嵌套成员 P 的可访问域是按以下方法定义的(注意,M 本身也可能是一个类型):The accessibility domain of a nested member M declared in a type T within a program P is defined as follows (noting that M might itself be a type):

  • 如果 M 的已声明可访问性为 public,则 M 的可访问域就是 T 的可访问域。If the declared accessibility of M is public, the accessibility domain of M is the accessibility domain of T.

  • 如果 M 的已声明可访问性为 protected internal,则 M 的可访问域就是 T 的可访问域与 P 的程序文本和从 T 派生的(在 P 之外声明的)任何类型的程序文本之间的交集。If the declared accessibility of M is protected internal, the accessibility domain of M is the intersection of the accessibility domain of T with the program text of P and the program text of any type derived from T declared outside P.

  • 如果 M 的已声明可访问性为 protected,则 M 的可访问域就是 T 的可访问域与 T 的程序文本和从 T 派生的任何类型的程序文本之间的交集。If the declared accessibility of M is protected, the accessibility domain of M is the intersection of the accessibility domain of T with the program text of T and any type derived from T.

  • 如果 M 的已声明可访问性为 internal,则 M 的可访问域就是 T 的可访问域与 P 的程序文本之间的交集。If the declared accessibility of M is internal, the accessibility domain of M is the intersection of the accessibility domain of T with the program text of P.

  • 如果 M 的已声明可访问性为 private,则 M 的可访问域就是 T 的程序文本。If the declared accessibility of M is private, the accessibility domain of M is the program text of T.

类型名称Type Names

常规类型系统对名称只有两种限制:The common type system imposes only two restrictions on names:

  • 所有的名称都按 Unicode(16 位)字符串进行编码。All names are encoded as strings of Unicode (16-bit) characters.

  • 名称不允许有嵌入的(16 位)0x0000 值。Names are not permitted to have an embedded (16-bit) value of 0x0000.

但是,大多数语言对类型名称都有附加限制。However, most languages impose additional restrictions on type names. 所有比较都是逐字节进行的,因此会区分大小写并与区域设置无关。All comparisons are done on a byte-by-byte basis, and are therefore case-sensitive and locale-independent.

尽管类型可能引用来自其他模块和程序集的类型,但类型在一个 .NET 模块内必须是完全定义的。Although a type might reference types from other modules and assemblies, a type must be fully defined within one .NET module. (但是,根据编译器支持的情况,它可以分成多个源代码文件。)类型名称只需要在命名空间内唯一。(Depending on compiler support, however, it can be divided into multiple source code files.) Type names need be unique only within a namespace. 要完全标识一个类型,其类型名称必须由包含此类型实现的命名空间加以限定。To fully identify a type, the type name must be qualified by the namespace that contains the implementation of the type.

基本类型和接口Base Types and Interfaces

一个类型可以从另一个类型继承值和行为。A type can inherit values and behaviors from another type. 常规类型系统不允许类型从多个基本类型进行继承。The common type system does not allow types to inherit from more than one base type.

一个类型可以实现任何数量的接口。A type can implement any number of interfaces. 要实现接口,类型必须实现该接口的所有虚拟成员。To implement an interface, a type must implement all the virtual members of that interface. 虚方法可以由派生的类型来实现,既可静态调用,也可动态调用。A virtual method can be implemented by a derived type and can be invoked either statically or dynamically.

类型成员Type Members

运行时允许您定义指定类型行为和状态的类型成员。The runtime enables you to define members of your type, which specifies the behavior and state of a type. 类型成员包括以下内容:Type members include the following:

字段Fields

字段描述并包含类型状态的一部分。A field describes and contains part of the type's state. 字段可以是运行时支持的任何类型。Fields can be of any type supported by the runtime. 字段通常是 privateprotected,因此只能在类内部或从派生类访问。Most commonly, fields are either private or protected, so that they are accessible only from within the class or from a derived class. 如果可以从类型外部修改字段值,通常使用属性集访问器。If the value of a field can be modified from outside its type, a property set accessor is typically used. 公开的字段通常是只读的,可以为以下两种类型:Publicly exposed fields are usually read-only and can be of two types:

  • 常量,在设计时赋值。Constants, whose value is assigned at design time. 尽管没有使用 static(在 Visual Basic 中为 Shared)关键字定义,但它们都是类的静态成员。These are static members of a class, although they are not defined using the static (Shared in Visual Basic) keyword.

  • 只读变量,可以在类构造函数中赋值。Read-only variables, whose values can be assigned in the class constructor.

下面的示例演示只读字段的这两种用法。The following example illustrates these two usages of read-only fields.

using System;

public class Constants
{
   public const double Pi = 3.1416;
   public readonly DateTime BirthDate;
   
   public Constants(DateTime birthDate)
   {
      this.BirthDate = birthDate;
   }
}

public class Example
{
   public static void Main()
   {
      Constants con = new Constants(new DateTime(1974, 8, 18));
      Console.Write(Constants.Pi + "\n");
      Console.Write(con.BirthDate.ToString("d") + "\n");
   }
}
// The example displays the following output if run on a system whose current
// culture is en-US:
//    3.1416
//    8/18/1974
Public Class Constants
   Public Const Pi As Double = 3.1416
   Public ReadOnly BirthDate As Date
   
   Public Sub New(birthDate As Date)
      Me.BirthDate = birthDate
   End Sub
End Class

Public Module Example
   Public Sub Main()
      Dim con As New Constants(#8/18/1974#)
      Console.WriteLine(Constants.Pi.ToString())
      Console.WriteLine(con.BirthDate.ToString("d"))
   End Sub
End Module
' The example displays the following output if run on a system whose current
' culture is en-US:
'    3.1416
'    8/18/1974

属性Properties

属性命名类型的值或状态,并定义获得或设置属性值的方法。A property names a value or state of the type and defines methods for getting or setting the property's value. 属性可以是基元类型、基元类型的集合、用户定义的类型或用户定义类型的集合。Properties can be primitive types, collections of primitive types, user-defined types, or collections of user-defined types. 属性通常用于使类型的公共接口独立于类型的实际表示形式。Properties are often used to keep the public interface of a type independent from the type's actual representation. 这使属性能够反映不直接在类中存储的值(例如,当属性返回计算值时)或能够在将值赋给私有字段前进行验证。This enables properties to reflect values that are not directly stored in the class (for example, when a property returns a computed value) or to perform validation before values are assigned to private fields. 下面的示例演示后一种模式。The following example illustrates the latter pattern.

using System;

public class Person
{
   private int m_Age;
   
   public int Age
   { 
      get { return m_Age; }
      set {
         if (value < 0 || value > 125)
         {
            throw new ArgumentOutOfRangeException("The value of the Age property must be between 0 and 125.");
         }
         else
         {
            m_Age = value;
         }         
      }
   }
}
Public Class Person
   Private m_Age As Integer
   
   Public Property Age As Integer
      Get
         Return m_Age
      End Get
      Set
         If value < 0 Or value > 125 Then
            Throw New ArgumentOutOfRangeException("The value of the Age property must be between 0 and 125.")
         Else
            m_Age = value
         End If
      End Set
   End Property
End Class

除了包含属性本身之外,包含可读属性的类型的 Microsoft 中间语言 (MSIL) 还包含 get_propertyname 方法,包含可写属性的类型的 MSIL 还包含 set_propertyname 方法。In addition to including the property itself, the Microsoft intermediate language (MSIL) for a type that contains a readable property includes a get_propertyname method, and the MSIL for a type that contains a writable property includes a set_propertyname method.

方法Methods

方法描述可用于类型的操作。A method describes operations that are available on the type. 方法的签名指定其所有参数和返回值可使用的类型。A method's signature specifies the allowable types of all its parameters and of its return value.

尽管大多数方法都定义方法调用所需的参数的确切数目,但某些方法支持可变数目的参数。Although most methods define the precise number of parameters required for method calls, some methods support a variable number of parameters. 这些方法的最后声明的参数用 ParamArrayAttribute 特性标记。The final declared parameter of these methods is marked with the ParamArrayAttribute attribute. 语言编译器通常会提供一个关键字(例如,在 C# 中为 params,在 Visual Basic 中为 ParamArray),使得不必显式使用 ParamArrayAttributeLanguage compilers typically provide a keyword, such as params in C# and ParamArray in Visual Basic, that makes explicit use of ParamArrayAttribute unnecessary.

构造函数Constructors

构造函数是一种特殊类型的方法,可创建类或结构的新实例。A constructor is a special kind of method that creates new instances of a class or structure. 像任何其他方法一样,构造函数可以包含参数,但是它不返回值(即它返回 void)。Like any other method, a constructor can include parameters; however, constructors have no return value (that is, they return void).

如果类的源代码没有显式定义构造函数,则编译器包含一个无参数构造函数。If the source code for a class does not explicitly define a constructor, the compiler includes a parameterless constructor. 但是,如果某个类的源代码只定义参数化的构造函数,则 Visual Basic 和 C# 编译器将不会生成无参数构造函数。However, if the source code for a class defines only parameterized constructors, the Visual Basic and C# compilers do not generate a parameterless constructor.

如果一个结构的源代码定义多个构造函数,则这些构造函数必须是参数化的;结构不能定义无参数构造函数,并且编译器不会为结构或其他值类型生成无参数构造函数。If the source code for a structure defines constructors, they must be parameterized; a structure cannot define a parameterless constructor, and compilers do not generate parameterless constructors for structures or other value types. 所有值类型都具有隐式无参数构造函数。All value types do have an implicit parameterless constructor. 此构造函数由公共语言运行时实现,并且将该结构的所有字段都初始化为其默认值。This constructor is implemented by the common language runtime and initializes all fields of the structure to their default values.

事件Events

事件定义可以响应的事情,并定义订阅、取消订阅及引发事件的方法。An event defines an incident that can be responded to, and defines methods for subscribing to, unsubscribing from, and raising the event. 事件通常用于通知其他类型的状态改变。Events are often used to inform other types of state changes. 有关详细信息,请参阅事件For more information, see Events.

嵌套类型Nested Types

嵌套类型是作为某其他类型的成员的类型。A nested type is a type that is a member of some other type. 嵌套类型应与其包含类型紧密关联,并且不得用作通用类型。Nested types should be tightly coupled to their containing type and must not be useful as a general-purpose type. 在声明类型使用和创建嵌套类型实例时,嵌套类型很有用,但不在公共成员中公开嵌套类型的使用。Nested types are useful when the declaring type uses and creates instances of the nested type, and use of the nested type is not exposed in public members.

嵌套类型可能会使有些开发人员感到困惑,因此除非有必要的理由,否则嵌套类型不应是公开可见的。Nested types are confusing to some developers and should not be publicly visible unless there is a compelling reason for visibility. 在设计完善的库中,开发人员几乎不需要使用嵌套类型实例化对象或声明变量。In a well-designed library, developers should rarely have to use nested types to instantiate objects or declare variables.

类型成员的特征Characteristics of Type Members

通用类型系统允许类型成员具有多种特征,但并不要求语言能支持所有这些特征。The common type system allows type members to have a variety of characteristics; however, languages are not required to support all these characteristics. 下表介绍了这些成员特征。The following table describes member characteristics.

特征Characteristic 可应用到Can apply to 说明Description
abstractabstract 方法、属性和事件Methods, properties, and events 类型不提供方法的实现。The type does not supply the method's implementation. 继承或实现抽象方法的类型必须提供方法的实现。Types that inherit or implement abstract methods must supply an implementation for the method. 只有当派生的类型本身是抽象类型的时候,情况例外。The only exception is when the derived type is itself an abstract type. 所有的抽象方法都是虚的。All abstract methods are virtual.
private、family、assembly、family 和 assembly、family 或 assembly,或者 publicprivate, family, assembly, family and assembly, family or assembly, or public 全部All 定义成员的可访问性:Defines the accessibility of the member:

privateprivate
只能在与成员相同的类型或在嵌套类型中访问。Accessible only from within the same type as the member, or within a nested type.

familyfamily
在与成员相同的类型中和从它继承的派生类型访问。Accessible from within the same type as the member, and from derived types that inherit from it.

程序集assembly
只能在定义该类型的程序集中访问。Accessible only in the assembly in which the type is defined.

family 和 assemblyfamily and assembly
只能从同时具备族和程序集访问权的类型进行访问。Accessible only from types that qualify for both family and assembly access.

family 或 assemblyfamily or assembly
只能从具备族和程序集访问权的类型进行访问。Accessible only from types that qualify for either family or assembly access.

publicpublic
可从任何类型访问。Accessible from any type.
finalfinal 方法、属性和事件Methods, properties, and events 虚方法不能在派生类型中被重写。The virtual method cannot be overridden in a derived type.
initialize-onlyinitialize-only 字段Fields 该值只能被初始化,不能在初始化之后写入。The value can only be initialized, and cannot be written after initialization.
实例instance 字段、方法、属性和事件Fields, methods, properties, and events 如果成员未标记为 static(C# 和 C++)、Shared (Visual Basic)、virtual(C# 和 C++)或 Overridable (Visual Basic),则它是一个实例成员(没有实例关键字)。If a member is not marked as static (C# and C++), Shared (Visual Basic), virtual (C# and C++), or Overridable (Visual Basic), it is an instance member (there is no instance keyword). 内存中这些成员的副本数将会像使用它们的对象数一样多。There will be as many copies of such members in memory as there are objects that use it.
文本literal 字段Fields 分配给该字段的值是一个内置值类型的固定值(在编译时已知)。The value assigned to the field is a fixed value, known at compile time, of a built-in value type. 文本字段有时指的是常数。Literal fields are sometimes referred to as constants.
newslot 或 overridenewslot or override 全部All 定义成员如何与具有相同签名的继承成员进行交互:Defines how the member interacts with inherited members that have the same signature:

newslotnewslot
隐藏具有相同签名的继承成员。Hides inherited members that have the same signature.

overrideoverride
替换继承的虚方法的定义。Replaces the definition of an inherited virtual method.

默认为 newslot。The default is newslot.
静态static 字段、方法、属性和事件Fields, methods, properties, and events 成员属于定义它的类型,而不属于该类型的特定实例;即使不创建类型的实例,成员也会存在,并且它由该类型的所有实例共享。The member belongs to the type it is defined on, not to a particular instance of the type; the member exists even if an instance of the type is not created, and it is shared among all instances of the type.
virtualvirtual 方法、属性和事件Methods, properties, and events 此方法可以由派生类型实现,并且既可静态调用,也可动态调用。The method can be implemented by a derived type and can be invoked either statically or dynamically. 如果使用动态调用,在运行时执行调用的实例类型(而不是编译时已知的类型)将确定调用方法的哪一种实现。If dynamic invocation is used, the type of the instance that makes the call at run time (rather than the type known at compile time) determines which implementation of the method is called. 若要静态调用虚方法,可能必须将变量强制转换为使用所需方法版本的类型。To invoke a virtual method statically, the variable might have to be cast to a type that uses the desired version of the method.

重载Overloading

每个类型成员都有一个唯一的签名。Each type member has a unique signature. 方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。Method signatures consist of the method name and a parameter list (the order and types of the method's arguments). 可以在一种类型内定义具有相同名称的多种方法,只要这些方法的签名不同。Multiple methods with the same name can be defined within a type as long as their signatures differ. 当定义两种或多种具有相同名称的方法时,就称作重载。When two or more methods with the same name are defined, the method is said to be overloaded. 例如,在 System.Char 中,重载了 IsDigit 方法。For example, in System.Char, the IsDigit method is overloaded. 一个方法采用 CharOne method takes a Char. 另一个方法采用 StringInt32The other method takes a String and an Int32.

备注

返回类型不被视为方法签名的一部分。The return type is not considered part of a method's signature. 这意味着如果方法只是返回类型不同,就不能重载。That is, methods cannot be overloaded if they differ only by return type.

继承,重写和隐藏成员Inheriting, Overriding, and Hiding Members

派生类型继承其基类型的所有成员;也就是说,会在派生类型上定义这些成员,并供派生类型使用。A derived type inherits all members of its base type; that is, these members are defined on, and available to, the derived type. 继承成员的行为和质量可以通过以下两种方式来修改:The behavior or qualities of inherited members can be modified in two ways:

  • 派生类型可通过使用相同的签名定义一个新成员,从而隐藏继承的成员。A derived type can hide an inherited member by defining a new member with the same signature. 将先前的公共成员变成私有成员,或者为标记为 final 的继承方法定义新行为时,可以采取这种方法。This might be done to make a previously public member private or to define new behavior for an inherited method that is marked as final.

  • 派生类型可以重写继承的虚方法。A derived type can override an inherited virtual method. 重写方法提供了对方法的一种新定义,将根据运行时的值的类型,而不是编译时已知的变量类型来调用方法。The overriding method provides a new definition of the method that will be invoked based on the type of the value at run time rather than the type of the variable known at compile time. 只有在虚拟方法未标记为 final 且新方法至少可以像虚拟方法一样进行访问的情况下,方法才能重写虚拟方法。A method can override a virtual method only if the virtual method is not marked as final and the new method is at least as accessible as the virtual method.

请参阅See also