C事件与接口编程全解析
立即解锁
发布时间: 2025-08-21 00:06:07 阅读量: 2 订阅数: 8 


C#编程基础与实战技巧
### C# 事件与接口编程全解析
#### 1. 事件基础
事件是类或结构体的成员,而非类型。这意味着在处理事件时,有以下几个关键要点:
- 不能使用对象创建表达式(如 `new` 表达式)来创建事件对象。
- 事件必须在类或结构体中与其他成员一起声明,不能在可执行代码块中声明。
- 事件成员会与其他成员一起隐式且自动初始化为 `null`。
事件声明需要委托类型的名称,你可以选择声明一个新的委托类型,或者使用已有的委托类型。推荐使用 `EventHandler` 委托,它是 .NET BCL 预定义的委托类型,也是处理事件的标准委托。其声明如下:
```csharp
public delegate void EventHandler( object sender, EventArgs e );
```
#### 2. 事件的触发
事件成员本身只是存储需要调用的事件处理程序,只有当事件被触发时,这些处理程序才会执行。触发事件时,有以下注意事项:
- 在触发事件之前,需要检查事件是否为 `null`,以确保其中包含事件处理程序。
- 触发事件的操作类似于调用函数,使用事件名称后跟括号括起来的参数列表,且参数列表必须与事件的委托类型匹配。
以下是一个触发 `Elapsed` 事件的示例代码:
```csharp
if (Elapsed != null) // 确保有方法可执行
Elapsed (source, args); // 触发事件
```
下面是一个包含事件声明和触发代码的发布者类的示例:
```csharp
public class MyTimerClass
{
public event EventHandler Elapsed; // 声明事件
private void OnOneSecond(object source, EventArgs args)
{
if (Elapsed != null) // 确保有方法可执行
Elapsed(source, args);
}
// 以下代码确保 OnOneSecond 方法每秒被调用一次
...
}
```
#### 3. 事件的订阅
要为事件添加事件处理程序,处理程序的返回类型和签名必须与事件的委托类型相同。可以使用 `+=` 运算符来添加事件处理程序,处理程序可以是实例方法、静态方法、匿名方法或 lambda 表达式。
以下是添加事件处理程序的示例代码:
```csharp
Class instance Instance method
↓ ↓
mc.Elapsed += ca.TimerHandlerA; // 方法引用形式
mc.Elapsed += ClassB.TimerHandlerB; // 方法引用形式
↑ ↑
Event member Static method
mc.Elapsed += new EventHandler(cc.TimerHandlerC); // 委托形式
```
也可以使用匿名方法和 lambda 表达式来添加事件处理程序,示例如下:
```csharp
mc.Elapsed += (source, args) => // Lambda 表达式
{
Console.WriteLine("Lambda expression.");
};
mc.Elapsed += delegate(object source, EventArgs args) // 匿名方法
{
Console.WriteLine("Anonymous method.");
};
```
下面是一个完整的程序示例,展示了如何注册事件处理程序并触发事件:
```csharp
public class MyTimerClass { ... }
class ClassA
{
public void TimerHandlerA(object source, EventArgs args) // 事件处理程序
{
Console.WriteLine("Class A handler called");
}
}
class ClassB
{
public static void TimerHandlerB(object source, EventArgs args) // 静态方法
{
Console.WriteLine("Class B handler called");
}
}
class Program
{
static void Main( )
{
ClassA ca = new ClassA(); // 创建类对象
MyTimerClass mc = new MyTimerClass(); // 创建定时器对象
mc.Elapsed += ca.TimerHandlerA; // 添加处理程序 A -- 实例方法
mc.Elapsed += ClassB.TimerHandlerB; // 添加处理程序 B -- 静态方法
Thread.Sleep(2250);
}
}
```
该程序的输出结果为:
```plaintext
Class A handler called
Class B handler called
Class A handler called
Class B handler called
```
#### 4. 事件处理程序的移除
当不再需要某个事件处理程序时,应该使用 `-=` 运算符将其从事件中移除,以便垃圾回收器释放相关内存。示例代码如下:
```csharp
mc.Elapsed -= ca.TimerHandlerA; // 移除处理程序 A
```
以下是一个完整的示例,展示了如何在事件触发两次后移除 `ClassB` 的事件处理程序:
```csharp
...
mc.Elapsed += ca.TimerHandlerA; // 添加实例处理程序 A
mc.Elapsed += ClassB.TimerHandlerB; // 添加静态处理程序 B
Thread.Sleep(2250); // 睡眠超过 2 秒
mc.Elapsed -= ClassB.TimerHandlerB; // 移除静态处理程序 B
Console.WriteLine("Class B event handler removed");
Thread.Sleep(2250); // 睡眠超过 2 秒
```
该程序的输出结果为:
```plaintext
Class A handler called
Class B handler called
Class A handler called
Class B handler called
Class B event handler removed
Class A handler called
Class A handler called
```
#### 5. 标准事件的使用
GUI 编程是事件驱动的,C# 事件非常适合处理这种异步事件。Windows GUI 编程广泛使用事件,并且有一个标准的 .NET 框架模式,推荐遵循该模式。该模式的基础是 `EventHandler` 委托类型,其声明如下:
```csharp
public delegate void EventHandler(object sender, EventArgs e);
```
其中,第一个参数用于存储引发事件的对象的引用,类型为 `object`;第二个参数用于存储与应用程序相关的状态信息;返回类型为 `void`。
`EventHandler` 委托类型的第二个参数是 `EventArgs` 类的对象,该类声明在 `System` 命名空间中。需要注意的是,`EventArgs` 类本身不存储数据,它用于不需要传递数据的事件处理程序。如果需要传递数据,必须声明一个从 `EventArgs` 派生的自定义类,并包含相应的字段来存储数据。
以下是一个自定义 `EventArgs` 类的示例,用于存储字符串消息:
```csharp
public class MyTCEventArgs: EventArgs
{
public string Message; // 存储消息
public MyTCEventArgs(string s) // 构造函数设置消息
{
Message = s;
}
}
```
#### 6. 使用自定义委托
有两种方式可以使用自定义类来传递事件处理程序的第二个参数:
- **非泛型委托**:创建一个新的自定义委托,使用自定义类类型,并在事件代码的其他部分使用新的委托名称。示例代码如下:
```csharp
public delegate void MyTCEventHandler (object sender, MyTCEventArgs e);
```
- **泛型委托 `EventHandler<>`**:将自定义类的名称放
0
0
复制全文
相关推荐









