差别
这里会显示出您选择的修订版和当前版本之间的差别。
| 后一修订版 | 前一修订版 | ||
| csharp:系统关键字 [2025/11/17 15:44] – 创建 张叶安 | csharp:系统关键字 [2025/11/28 11:12] (当前版本) – [5. Event (事件) 关键词] 张叶安 | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| - | | 关键词 | + | ====== C# 系统关键词与修饰符 ====== |
| - | | public | + | |
| - | | sealed | + | 在 C# 中,修饰符(Modifiers)用于定义类型和成员的访问级别、继承行为以及其他特性。合理使用修饰符是实现封装、多态和代码管理的基础。 |
| - | | partial | 拆分 | + | |
| + | ===== 关键词速查表 ===== | ||
| + | |||
| + | ^ 关键词 ^ 含义 | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | |||
| + | ===== 详细解析与案例 ===== | ||
| + | |||
| + | ==== 1. 访问修饰符 (public / private) ==== | ||
| + | |||
| + | 这是最基础的封装概念。 | ||
| + | |||
| + | <code csharp> | ||
| + | public class User | ||
| + | { | ||
| + | // public: 外部可以随意读取和修改(通常建议配合属性使用) | ||
| + | public string NickName; | ||
| + | |||
| + | // private: 外部无法访问,只能在 User 类内部使用 | ||
| + | private string _password; | ||
| + | |||
| + | public void SetPassword(string pwd) | ||
| + | { | ||
| + | // 在类内部可以访问 private 变量 | ||
| + | _password = pwd; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== 2. 密封与分部 (sealed / partial) ==== | ||
| + | |||
| + | 这是你提到的重点关键词。 | ||
| + | |||
| + | **sealed (密封)** | ||
| + | 用于防止类被继承,或者防止方法被进一步重写。 | ||
| + | |||
| + | <code csharp> | ||
| + | // 这是一个最终版本,不允许其他人再继承修改它 | ||
| + | public sealed class FinalLogic | ||
| + | { | ||
| + | public void DoWork() { ... } | ||
| + | } | ||
| + | |||
| + | // 错误写法:编译器会报错 | ||
| + | // class MyClass : FinalLogic { } | ||
| + | </ | ||
| + | |||
| + | **partial (分部)** | ||
| + | 常用于多人协作或自动生成的代码。 | ||
| + | |||
| + | **文件 1: Person.Part1.cs** | ||
| + | <code csharp> | ||
| + | public partial class Person | ||
| + | { | ||
| + | public string Name { get; set; } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | **文件 2: Person.Part2.cs** | ||
| + | <code csharp> | ||
| + | public partial class Person | ||
| + | { | ||
| + | public void SayHello() | ||
| + | { | ||
| + | // 可以直接访问另一部分定义的 Name | ||
| + | Console.WriteLine(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | *注:编译时,这两个部分会被合并成一个完整的 `Person` 类。* | ||
| + | |||
| + | ==== 3. 多态与继承 (virtual / override / abstract) ==== | ||
| + | |||
| + | 这是面向对象编程的核心。 | ||
| + | |||
| + | <code csharp> | ||
| + | // 父类 | ||
| + | public class Animal | ||
| + | { | ||
| + | // virtual: 允许子类重写这个方法 | ||
| + | public virtual void Speak() | ||
| + | { | ||
| + | Console.WriteLine(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // 子类 | ||
| + | public class Dog : Animal | ||
| + | { | ||
| + | // override: 重写父类的逻辑 | ||
| + | public override void Speak() | ||
| + | { | ||
| + | Console.WriteLine(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // 抽象类案例 | ||
| + | public abstract class Shape | ||
| + | { | ||
| + | // abstract: 我不知道怎么算面积,子类必须自己写 | ||
| + | public abstract double GetArea(); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== 4. 静态 (static) ==== | ||
| + | |||
| + | 静态成员属于类,不属于对象。 | ||
| + | |||
| + | <code csharp> | ||
| + | public class Tools | ||
| + | { | ||
| + | // 静态变量:所有实例共享一份 | ||
| + | public static double Pi = 3.14159; | ||
| + | |||
| + | // 静态方法:直接通过 Tools.Add() 调用 | ||
| + | public static int Add(int a, int b) | ||
| + | { | ||
| + | return a + b; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // 调用方式 | ||
| + | double area = Tools.Pi * 10 * 10; // 不需要 new Tools() | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== 5. Event (事件) 关键词 ==== | ||
| + | |||
| + | 在 C# 中,**event** 关键词用于在类或对象中声明事件。事件允许类或对象在发生某些特定情况时通知其他类或对象。这是一种基于 **发布-订阅 (Publish-Subscribe)** 模式的机制。 | ||
| + | |||
| + | === 1. 核心概念 === | ||
| + | |||
| + | * **发布者 (Publisher)**:定义事件并决定何时触发事件的类。 | ||
| + | * **订阅者 (Subscriber)**:监听事件并在事件触发时执行特定操作的类。 | ||
| + | * **委托 (Delegate)**:事件底层的类型安全函数指针,定义了事件处理程序的签名。 | ||
| + | |||
| + | === 2. 语法结构 === | ||
| + | |||
| + | 声明一个事件通常包含两个步骤: | ||
| + | - 1. 定义委托(或者使用系统内置的 `EventHandler`)。 | ||
| + | - 2. 使用 `event` 关键词声明事件变量。 | ||
| + | |||
| + | <code csharp> | ||
| + | public delegate void MyEventHandler(string message); // 1. 定义委托 | ||
| + | public event MyEventHandler OnProcessCompleted; | ||
| + | </ | ||
| + | |||
| + | === 3. 实战案例 === | ||
| + | |||
| + | 以下是一个完整的控制台程序案例,模拟了一个视频编码器(发布者)和邮件服务(订阅者)。 | ||
| + | |||
| + | == 案例代码 == | ||
| + | |||
| + | <code csharp> | ||
| + | using System; | ||
| + | |||
| + | namespace EventDemo | ||
| + | { | ||
| + | // 1. 定义包含事件数据的类 (可选,但推荐) | ||
| + | public class VideoEventArgs : EventArgs | ||
| + | { | ||
| + | public string Title { get; set; } | ||
| + | } | ||
| + | |||
| + | // 2. 发布者:视频编码器 | ||
| + | public class VideoEncoder | ||
| + | { | ||
| + | // 声明事件:使用内置的 EventHandler< | ||
| + | // 这里的 event 关键词是核心 | ||
| + | public event EventHandler< | ||
| + | |||
| + | public void Encode(string title) | ||
| + | { | ||
| + | Console.WriteLine($" | ||
| + | System.Threading.Thread.Sleep(1000); | ||
| + | |||
| + | // 触发事件 | ||
| + | OnVideoEncoded(title); | ||
| + | } | ||
| + | |||
| + | // 按照约定,创建一个受保护的虚方法来触发事件 | ||
| + | protected virtual void OnVideoEncoded(string title) | ||
| + | { | ||
| + | // 检查是否有订阅者 (VideoEncoded != null) | ||
| + | VideoEncoded? | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // 3. 订阅者:邮件服务 | ||
| + | public class MailService | ||
| + | { | ||
| + | // 事件处理程序:签名必须与委托匹配 | ||
| + | public void OnVideoEncoded(object source, VideoEventArgs e) | ||
| + | { | ||
| + | Console.WriteLine($" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // 4. 主程序 | ||
| + | class Program | ||
| + | { | ||
| + | static void Main(string[] args) | ||
| + | { | ||
| + | var video = new VideoEncoder(); | ||
| + | var mailService = new MailService(); | ||
| + | |||
| + | // 订阅事件:使用 += 操作符 | ||
| + | video.VideoEncoded += mailService.OnVideoEncoded; | ||
| + | |||
| + | video.Encode(" | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | == 输出结果 == | ||
| + | |||
| + | <code text> | ||
| + | 正在编码视频: | ||
| + | 邮件服务:发送邮件,视频 ' | ||
| + | </ | ||
| + | |||
| + | === 4. 关键点总结 === | ||
| + | |||
| + | * **封装性**:`event` 关键词为委托实例提供了一层封装。在类的外部,客户端只能使用 `+=` (订阅) 和 `-=` (取消订阅),而不能直接使用 `=` 赋值(这会覆盖其他订阅者)或直接调用 `Invoke()`。 | ||
| + | * **空检查**:在触发事件前,务必检查事件是否为 `null`(即是否有订阅者),C# | ||
| + | * **命名规范**:事件通常命名为 `Name` 或 `OnName`,处理方法通常命名为 `OnName`。 | ||