C#:避免if(x为Foo){…} else if(x is Bar){…}用于数据结构

我有一系列数据结构,如:

abstract class Base {...} class Foo : Base {...} class Bar : Base {...} 

以及一个接受Base并根据它的子类转换它的方法:

 void Convert(Base b) { if (b is Foo) // Do the Foo conversion else if (b is Bar) // Do the Bar conversion ... 

显然这是一个糟糕的面向对象 – 转换方法必须知道Base的每个派生类,并且必须在每次扩展Base时进行更改。 解决这个问题的“正常”OO方法是使每个派生类的Base负责转换自身,例如

 abstract class Base { abstract Converted Convert(); ...} class Foo : Base { override Converted Convert(){...} ...} class Bar : Base { override Converted Convert(){...} ...} 

但是,在我编写的代码中,Base是一个纯数据结构(只有getter和setter – 没有逻辑),而且它在另一个我无权更改的程序集中。 有没有一种方法可以更好地构造代码,而不强制Base的派生类具有逻辑?

谢谢

如果你这样做会疼,那就不要那样做了。 根本问题是:

我有一个方法,需要一个Base ……

由于这是根本问题,请将其删除。 完全摆脱那种方法,因为它很糟糕。

替换为:

 void Convert(Foo foo) { // Do the Foo conversion } void Convert(Bar bar) { // Do the Bar conversion } 

现在没有方法可以说谎,并说它可以转换任何 Base ,而事实上它不能。

我遇到了类似的情况,并提出了一个类似于函数式语言模式匹配的解决方案。 这是语法:

请注意,在lambdas中,foo和bar被强类型化为各自的类型; 不需要施放。

 var convertedValue = new TypeSwitch(r) .ForType(foo => /* do foo conversion */) .ForType(bar => /* do bar conversion */) ).GetValue(); 

这是TypeSwitch类的实现:

 public class TypeSwitch { bool matched; T value; TResult result; public TypeSwitch(T value) { this.value = value; } public TypeSwitch ForType(Func caseFunc) where TSpecific : T { if (value is TSpecific) { matched = true; result = caseFunc((TSpecific)value); } return this; } public TResult GetValue() { if (!matched) { throw new InvalidCastException("No case matched"); } return result; } } 

我确信它可以清理,在大多数情况下,Eric Lippert说这个前提存在根本缺陷是正确的。 但是,如果你碰到一个案例,你唯一的另一个选择是一堆is和演员,我认为这是一个更清洁!