请解释 C# 中双分派(Double Dispatch)的概念,并说明在 C# 中实现双分派的具体方法。
考察说明
考查对多态分派机制的理解及在 C# 中实现双分派的能力。
回答思路
- 【回答框架 1】双分派是指在运行时根据两个对象的实际类型来决定调用哪个方法,而普通虚方法只根据接收者类型进行单分派。C# 默认只支持单分派,即编译时根据静态类型选择重载,运行时根据接收者动态类型选择虚方法。
- 【回答框架 2】实现双分派的核心模式是访问者模式(Visitor Pattern)。在访问者模式中,元素类定义一个 Accept 方法,接受访问者对象作为参数,并在 Accept 内部调用访问者针对该元素类型的重载方法,从而将分派从两个对象类型中解耦。
- 【回答框架 3】具体实现步骤:定义访问者接口,包含针对每种元素类型的重载方法(如 Visit(ElementA)、Visit(ElementB));定义元素基类或接口,声明 Accept(Visitor) 方法;每个具体元素类实现 Accept,调用 visitor.Visit(this),由于 this 的静态类型是具体元素类,编译器会选择正确的重载,实现双分派。
- 【回答框架 4】在 C# 中,还可以利用动态类型(dynamic)简化实现,通过 dynamic 关键字在运行时进行动态分派,但会带来性能开销和类型安全损失。访问者模式是更推荐的方式,它保持类型安全且结构清晰。
- 【回答框架 5】双分派常用于算法与数据结构分离的场景,如编译器中的 AST 遍历、图形绘制中的形状与渲染器交互等。它提高了扩展性,但增加了类层次结构的复杂度。
- 【关键点 1】C# 默认只支持单分派,双分派需通过访问者模式或 dynamic 实现。
- 【关键点 2】访问者模式通过元素类的 Accept 方法调用访问者的重载方法,实现基于两个对象类型的分派。
- 【关键点 3】使用 dynamic 可实现双分派但牺牲类型安全和性能。
- 【关键点 4】双分派适用于算法与对象结构分离的场景,如 AST 遍历。