下面的简单示例演示用于在基类中声明事件,以便也可以从派生类引发它们的标准方法。 此模式广泛用于 .NET 类库中的 Windows 窗体类。

创建可以用作其他类的基类的类时,应考虑到以下事实:事件是特殊类型的委托,只能从声明它们的类中进行调用。 派生类不能直接调用在基类中声明的事件。 虽然有时可能需要只能由基类引发的事件,不过在大多数情况下,应使派生类可以调用基类事件。 为此,可以在包装事件的基类中创建受保护的调用方法。 通过调用或重写此调用方法,派生类可以间接调用事件。

不要在基类中声明虚拟事件并在派生类中重写它们。 C# 编译器不会处理这些事件,并且无法预知派生事件的订阅者是否实际上会订阅基类事件。

namespace BaseClassEvents // Special EventArgs class to hold info about Shapes. public class ShapeEventArgs : EventArgs public ShapeEventArgs(double area) NewArea = area; public double NewArea { get; } // Base class event publisher public abstract class Shape protected double _area; public double Area get => _area; set => _area = value; // The event. Note that by using the generic EventHandler<T> event type // we do not need to declare a separate delegate type. public event EventHandler<ShapeEventArgs> ShapeChanged; public abstract void Draw(); //The event-invoking method that derived classes can override. protected virtual void OnShapeChanged(ShapeEventArgs e) // Safely raise the event for all subscribers ShapeChanged?.Invoke(this, e); public class Circle : Shape private double _radius; public Circle(double radius) _radius = radius; _area = 3.14 * _radius * _radius; public void Update(double d) _radius = d; _area = 3.14 * _radius * _radius; OnShapeChanged(new ShapeEventArgs(_area)); protected override void OnShapeChanged(ShapeEventArgs e) // Do any circle-specific processing here. // Call the base class event invocation method. base.OnShapeChanged(e); public override void Draw() Console.WriteLine("Drawing a circle"); public class Rectangle : Shape private double _length; private double _width; public Rectangle(double length, double width) _length = length; _width = width; _area = _length * _width; public void Update(double length, double width) _length = length; _width = width; _area = _length * _width; OnShapeChanged(new ShapeEventArgs(_area)); protected override void OnShapeChanged(ShapeEventArgs e) // Do any rectangle-specific processing here. // Call the base class event invocation method. base.OnShapeChanged(e); public override void Draw() Console.WriteLine("Drawing a rectangle"); // Represents the surface on which the shapes are drawn // Subscribes to shape events so that it knows // when to redraw a shape. public class ShapeContainer private readonly List<Shape> _list; public ShapeContainer() _list = new List<Shape>(); public void AddShape(Shape shape) _list.Add(shape); // Subscribe to the base class event. shape.ShapeChanged += HandleShapeChanged; // ...Other methods to draw, resize, etc. private void HandleShapeChanged(object sender, ShapeEventArgs e) if (sender is Shape shape) // Diagnostic message for demonstration purposes. Console.WriteLine($"Received event. Shape area is now {e.NewArea}"); // Redraw the shape here. shape.Draw(); class Test static void Main() //Create the event publishers and subscriber var circle = new Circle(54); var rectangle = new Rectangle(12, 9); var container = new ShapeContainer(); // Add the shapes to the container. container.AddShape(circle); container.AddShape(rectangle); // Cause some events to be raised. circle.Update(57); rectangle.Update(7, 7); // Keep the console window open in debug mode. Console.WriteLine("Press any key to continue..."); Console.ReadKey(); /* Output: Received event. Shape area is now 10201.86 Drawing a circle Received event. Shape area is now 49 Drawing a rectangle
  • C# 编程指南
  • 访问修饰符
  • 在 Windows 窗体中创建事件处理程序
  •