下面的简单示例演示用于在基类中声明事件,以便也可以从派生类引发它们的标准方法。 此模式广泛用于 .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 窗体中创建事件处理程序