通过


C# 类

小窍门

开发软件的新手? 首先开始 学习入门 教程。 需要为具有行为和状态的对象建模后,你将遇到类。

是否在其他语言中有经验? C# 类类似于 Java 或 C++ 中的类。 浏览 C# 特定模式的 对象初始值设定项 部分,并查看以数据为中心的替代方法 记录

是定义对象的蓝图的引用类型。 创建类类型的变量时,该变量保存对托管堆上的对象的 引用 。 变量不保存对象数据本身。 将类变量分配给另一个变量会复制引用,因此两个变量都指向同一对象。 类是定义 C# 中的自定义类型的最常见方法。 当您需要在引用之间实现复杂行为、继承或共享身份时,请使用它们。

何时使用类

在以下情况下使用类:

  • 该类型具有复杂行为或管理可变状态。
  • 需要继承才能创建具有派生专用化的基类,或创建扩展现有类的派生类型。
  • 实例表示共享身份,而不是仅仅持有相等值的对象。 对同一对象的两个引用应保持同步。
  • 该类型较大或生存期较长,受益于堆分配和引用语义。

声明类

使用 class 关键字后跟类型名称定义类。 可选的 访问修饰符 控制可见性。 默认值为 internal。 指定 public 以允许来自其他程序集的调用方使用你的类型。

public class Customer
{
    public string Name { get; set; }

    public Customer(string name) => Name = name;
}

类正文包含字段、属性、方法和事件,统称为 类成员。 该名称必须是有效的 C# 标识符名称

创建对象

类定义类型,但它不是对象本身。 使用关键字创建对象(类new):

var customer = new Customer("Allison");
Console.WriteLine(customer.Name); // Allison

该变量 customer 保存对对象的引用,而不是对象本身。 可以将多个变量分配给同一对象。 通过一个引用进行的更改在另一个引用中也可见。

var c1 = new Customer("Grace");
var c2 = c1; // both variables reference the same object

c2.Name = "Hopper";
Console.WriteLine(c1.Name); // Hopper — c1 sees the change made through c2

此引用共享行为是类和 结构之间的一个区别。 使用结构时,赋值将复制数据。 更重要的是,类支持 继承。 可以构建层次结构,其中派生类型重用基类的行为并进行专门化。 结构体不能参与继承层次结构。 有关区别的详细信息,请参阅 “值类型”和“引用类型”。

构造函数和初始化

创建实例时,需要将其字段和属性初始化为有用的值。 C# 提供了多种方法:字段初始值设定项、构造函数参数、主构造函数和必需属性。

字段初始值设定项 直接在字段声明上设置默认值:

public class Container
{
    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;
}

主构造函数和字段初始值设定项可以协同工作:字段初始值设定 _capacity = capacity 项使用主构造函数参数作为其值。 通过此模式,可以使用单个简洁声明在字段中捕获构造函数参数。

必需的属性 强制调用方通过对象初始值设定项设置特定属性:

public class Person
{
    public required string FirstName { get; set; }
    public required string LastName { get; set; }
}
// var missing = new Person(); // Error: required properties not set
var person = new Person { FirstName = "Grace", LastName = "Hopper" };
Console.WriteLine($"{person.FirstName} {person.LastName}"); // Grace Hopper

有关构造函数模式(包括参数验证和构造函数链接)的更深入的了解,请参阅 构造函数

静态类

无法实例化的 static 类仅包含静态成员。 使用静态类来组织不对实例数据进行操作的实用工具方法:

static class MathHelpers
{
    public static double CircleCircumference(double radius) =>
        2 * Math.PI * radius;
}
double circumference = MathHelpers.CircleCircumference(5.0);
Console.WriteLine($"Circumference: {circumference:F2}"); // Circumference: 31.42

.NET类库包括许多静态类,例如 MathConsole。 静态类是隐式密封的。 无法从它派生或实例化它。

对象初始值设定项

使用对象初始值设定项 可以在创建对象时设置属性,而无需为每个值组合编写构造函数:

class ConnectionOptions
{
    public string Host { get; init; } = "localhost";
    public int Port { get; init; } = 80;
    public bool UseSsl { get; init; }
}
var options = new ConnectionOptions
{
    Host = "db.example.com",
    Port = 5432,
    UseSsl = true
};
Console.WriteLine($"{options.Host}:{options.Port} (SSL: {options.UseSsl})");
// db.example.com:5432 (SSL: True)

对象初始值设定项使用具有 setinit 访问器的任何可访问属性。 它们自然地与 required 属性和接受某些参数的构造函数组合在一起,同时让调用方设置其他参数。

当属性是 集合时,可以使用 集合表达式(C# 引用) 初始化该对象。

继承

类支持 继承。 可以定义重用、扩展或修改现有类的行为的新类。 从中继承的 类是基类,新类是 派生类

var manager = new Manager("Satya", "Engineering");
Console.WriteLine($"{manager.Name} manages {manager.Department}");
// Satya manages Engineering

类可以从一个基类继承并实现多个接口。 派生类继承除构造函数以外的基类的所有成员。 有关详细信息,请参阅 继承接口

另见