类简介
引用类型
定义为 class
的类型是引用类型。 在运行时,如果声明引用类型的变量,此变量就会一直包含值 null
,直到使用 new
运算符显式创建类实例,或直到为此变量分配已在其他位置创建的兼容类型,如下面的示例所示:
//Declaring an object of type MyClass.
MyClass mc = new MyClass();
//Declaring another object of the same type, assigning it the value of the first object.
MyClass mc2 = mc;
创建对象时,在该托管堆上为该特定对象分足够的内存,并且该变量仅保存对所述对象位置的引用。 对象使用的内存由 CLR 的自动内存管理功能(称为垃圾回收)回收。 有关垃圾回收的详细信息,请参阅自动内存管理和垃圾回收。
声明类
使用后跟唯一标识符的 class
关键字可以声明类,如下例所示:
//[access modifier] - [class] - [identifier]
public class Customer
{
// Fields, properties, methods and events go here...
}
可选访问修饰符位于 class
关键字前面。 class
类型的默认访问权限为 internal
。 此例中使用的是 public
,因此任何人都可创建此类的实例。 类的名称遵循 class
关键字。 类名称必须是有效的 C# 标识符名称。 定义的其余部分是类的主体,其中定义了行为和数据。 类上的字段、属性、方法和事件统称为类成员。
创建对象
虽然它们有时可以互换使用,但类和对象是不同的概念。 类定义对象类型,但不是对象本身。 对象是基于类的具体实体,有时称为类的实例。
可通过使用 new
关键字,后跟类的名称来创建对象,如下所示:
Customer object1 = new Customer();
创建类的实例后,会将一个该对象的引用传递回程序员。 在上一示例中,object1
是对基于 Customer
的对象的引用。 该引用指向新对象,但不包含对象数据本身。 事实上,可以创建对象引用,而完全无需创建对象本身:
Customer object2;
不建议创建不引用对象的对象引用,因为尝试通过这类引用访问对象会在运行时失败。 但是,但实际上引用可以引用某个对象,方法是创建新对象,或者将其分配给现有对象,例如:
Customer object3 = new Customer();
Customer object4 = object3;
此代码创建指向同一对象的两个对象引用。 因此,通过 object3
对对象做出的任何更改都会在后续使用 object4
时反映出来。 由于基于类的对象是通过引用来实现其引用的,因此类被称为引用类型。
构造函数和初始化
前面的部分介绍了声明类类型并创建该类型的实例的语法。 创建类型的实例时,需要确保其字段和属性已初始化为有用的值。 可通过多种方式初始化值:
- 接受默认值
- 字段初始化表达式
- 构造函数参数
- 对象初始值设定项
每个 .NET 类型都有一个默认值。 通常,对于数字类型,该值为 0,对于所有引用类型,该值为 null
。 如果默认值在应用中是合理的,则可以依赖于该默认值。
当 .NET 默认值不是正确的值时,可以使用字段初始化表达式设置初始值:
public class Container
{
// Initialize capacity field to a default value of 10:
private int _capacity = 10;
}
可以通过定义负责设置初始值的构造函数来要求调用方提供初始值:
public class Container
{
private int _capacity;
public Container(int capacity) => _capacity = capacity;
}
从 C# 12 开始,可以将主构造函数定义为类声明的一部分:
public class Container(int capacity)
{
private int _capacity = capacity;
}
向类名添加参数可定义主构造函数。 这些参数在包含其成员的类正文中可用。 可以将其用于初始化字段或需要它们的任何其他位置。
还可以对某个属性使用 required
修饰符,并允许调用方使用对象初始值设定项来设置该属性的初始值:
public class Person
{
public required string LastName { get; set; }
public required string FirstName { get; set; }
}
添加 required
关键字要求调用方必须将这些属性设置为 new
表达式的一部分:
var p1 = new Person(); // Error! Required properties not set
var p2 = new Person() { FirstName = "Grace", LastName = "Hopper" };
类继承
类完全支持继承,这是面向对象的编程的基本特点。 创建类时,可以从其他任何未定义为 sealed
的类继承。 其他类可以从你的类继承并替代类虚拟方法。 此外,你可以实现一个或多个接口。
继承是通过使用派生来完成的,这意味着类是通过使用其数据和行为所派生自的基类来声明的。 基类通过在派生的类名称后面追加冒号和基类名称来指定,如:
public class Manager : Employee
{
// Employee fields, properties, methods and events are inherited
// New Manager fields, properties, methods and events go here...
}
类声明包括基类时,它会继承基类除构造函数外的所有成员。 有关详细信息,请参阅继承。
C# 中的类只能直接从基类继承。 但是,因为基类本身可能继承自其他类,因此类可能间接继承多个基类。 此外,类可以支持实现一个或多个接口。 有关详细信息,请参阅接口。
类可以声明为 abstract
。 抽象类包含抽象方法,抽象方法包含签名定义但不包含实现。 抽象类不能实例化。 只能通过可实现抽象方法的派生类来使用该类。 与此相反,密封类不允许其他类继承。 有关详细信息,请参阅抽象类、密封类和类成员。
类定义可以在不同的源文件之间分割。 有关详细信息,请参阅分部类和方法。
C# 语言规范
有关详细信息,请参阅 C# 语言规范。 该语言规范是 C# 语法和用法的权威资料。