例如
BaseClass MyBase() { public int Add(BaseClass next) { if (this is InheritedA && next is InheritedA) return 1; else if (this is InheritedA && next is InheritedB) return 2; else if (this is InheritedB && next is InheritedA) return 3; else if (this is InheritedB && next is InheritedB) return 4; } }
其中InheritedA和InheritedB是其继承的类.实际上,有更多的Inherited类,Add根据其操作数的顺序和类型返回不同的结果.
我正在考虑使用多态和重载来重写它,但是,它变得相当复杂,我必须引入一个帮助方法来解析任一端的类型.
例如
InheritedA myA() { public override int Add(BaseClass next) { return next.AddTo(this); } }
现在我必须将AddTo放入BaseClass,并在继承的类中重写它.
InheritedA myA() { public override int AddTo(InheritedA next) { return 1; } public override int AddTo(InheritedB next) { return 3; } } BaseClass myBase() { public abstract int Add(BaseClass next); public abstract int AddTo(InheritedA next); public abstract int AddTo(InheritedB next); }
有没有更好的方法呢?
解决方法
您正在实现的模式称为双虚拟调度.
单个虚拟分派根据接收器的运行时类型和参数的编译时类型选择要调用的方法.这是传统的虚拟调度:
abstract class Animal {} class Tiger : Animal {} class Giraffe : Animal {} class B { public virtual void M(Tiger x) {} public virtual void M(Animal x) {} } class D : B { public override void M(Tiger x) {} public override void M(Animal x) {} } ... B b = whatever; Animal a = new Tiger(); b.M(a);
叫哪种方法? B.M(老虎)和D.M(老虎)未被选中;我们根据参数的编译时类型拒绝它们,这是Animal.但是我们根据是否是新的B()或新的D()选择是否在运行时调用B.M(动物)或D.M(动物).
双虚拟分派根据两件事的运行时类型选择调用哪个方法.如果C#支持双虚拟调度,它不支持,那么运行时调度将转到B.M(Tiger)或D.M(Tiger),即使参数的编译时类型是Animal.
但是,C#4支持动态调度.如果你说
dynamic b = whatever; dynamic a = new Tiger(); b.M(a);
然后,M的分析将完全在运行时使用b和a的运行时类型完成.这明显变慢,但确实有效.
或者,如果您想进行双重虚拟调度并尽可能在编译时完成分析,那么标准的方法是实现访问者模式,您可以轻松地在互联网上查找.