基于类型切换行为的最佳方法

可能重复:
C# – “开启类型”有比这更好的选择吗?

考虑经典:

class Widget { } class RedWidget : Widget { } class BlueWidget : Widget { } 

在大多数情况下,在我的UI中,我可以将所有Widget视为相同。 但是,有一些细微的差别,我需要或switch

可能的方法:

枚举指标 – 由构造函数设置

 enum WidgetVariety { Red, Blue } class Widget { public WidgetVariety Variety { get; protected set; } } class RedWidget : Widget { public RedWidget() { Variety = Red; } } // Likewise for BlueWidget... switch (mywidget.Variety) { case WidgetVariety.Red: // Red specific GUI stuff case WidgetVariety.Blue: // Blue specific GUI stuff } 

用途is

 Widget w = ...; if (w is RedWidget) { (RedWidget)w ... } else if (w is BlueWidget) { (BlueWidget)w ... } 

我采用这种方法的原因是1)大多数代码已经用这种方式编写,但更加丑陋。 2)90%的代码是相同的 – 基本上只需要根据类型对GridView中的一列进行不同的处理。

你会推荐哪个? (或者任何人都有更好的解决方案?)


编辑我知道我可能会被推荐给访客模式,但在这种情况下,这似乎很复杂,因为稀疏的细微差别。

编辑2因此,我很难解决的一个特殊区别是这个列在两种类型之间是不同的。 在一种情况下,它检索bool值,并将其分配给网格单元格。 在另一种情况下,它获取字符串值。

我想在这种情况下,我可以明确地定义:

 public object virtual GetColumn4Data(); public override GetColumn4Data() { return m_boolval; } public override GetColumn4Data() { return m_mystring; } 

由于使用了object ,我最初感觉不对。 但是,这我在单元格中分配的属性的类型,所以当然这是有道理的!

今天办公室太长了似乎……

还有另一种可能性。 使用虚拟调度:

 class Widget { public virtual void GuiStuff() { } } class RedWidget : Widget { public override void GuiStuff() { //... red-specific GUI stuff base.GuiStuff(); } } class BlueWidget : Widget { public override void GuiStuff() { //... blue-specific GUI stuff base.GuiStuff(); } } 

子类型多态性是最好的解决方案,避免这种检查是OO创建的主要原因之一。

Widget可能有一个方法DoSomething() (可能是抽象),然后RedWidgetBlueWidget会覆盖它。

另请参阅Martin Fowler的替换条件多态性 :

看到:您有一个条件,根据对象的类型选择不同的行为。

重构:将条件的每一条腿移动到子类中的重写方法。 使原始方法抽象化。

对于您在Edit#2下的问题,您可以使用generics类使类型在子类之间变化,但根据您的设计,它可能适用于您,也可能不适合您。 它可能会导致其他艰难的设计决策。

粗略的例子:

 internal abstract class BaseClass { protected object mValue; // could also be defined as a T in BaseClass public object GetColumn4Data { get { return mValue; } } } // this is a group of classes with varying type internal abstract class BaseClass : BaseClass { public T GetTypedColumn4Data { get { return (T)mValue; } set { mValue = value; } } } // these are not really necessary if you don't plan to extend them further // in that case, you would mark BaseClass sealed instead of abstract internal sealed class BoolSubClass : BaseClass { // no override necessary so far } internal sealed class StringSubClass : BaseClass { // no override necessary so far } 

但请注意,您无法真正获得在某些属性或方法上具有不同返回类型的单个引用类型。 BaseClass引用最多只返回一般类型(如object )。