2012-04-11 85 views
5

可能重复:
C# - Is there a better alternative than this to ‘switch on type’?的最佳方式基于类型

考虑经典:

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

在大多数情况下,在我的UI,我可以对待所有Widget一样。但是,有一些细微的差异,我需要通过ifswitch

可能的方法:

枚举指标 - 通过构造方法设置

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。但是,我分配给单元格的属性的类型,所以当然是这很有道理!

今天在办公室时间太长了......

+3

听起来好像你说的是:由于大部分代码已经写得很差,你需要通过编写更难看的难以维护的代码来延续这一趋势。 – 2012-04-11 22:49:47

+0

如果你的子类有一个不同的类型,那么也许基类应该是通用的。然后它变成'public virtual T GetColumn4Data(); ... public override bool GetColumn4Data(){return m_boolval; } ... public override string GetColumn4Data(){return m_mystring; }' – 2012-04-11 23:30:43

+0

@Sahuagin - 请保存更大的代码片段以获取答案。评论不公平。 – 2012-04-11 23:57:31

回答

9

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

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(); 
    } 
} 
+0

当然....看我的编辑2 :-) – 2012-04-11 22:57:46

5

Subtype polymorphism是最好的解决办法,以避免这种检查是OO创建的主要原因之一。

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

另见Martin Fowler的Replace Conditional with Polymorphism

看:你有一个条件是选择依赖于对象的类型不同的行为。

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

+2

我不同意[这种]多态性是“OO为什么被创造”的观点;它更像是一些“OO语言”的*效果。但是,其他位的+1。 (有更多的多态性比无聊 - 而且是危险的 - 例如在C#/ Java中发现的单派遣子类型。) – 2012-04-11 23:05:39

+0

@pst我看到你的观点,有趣的话题 – jorgehmv 2012-04-11 23:25:01

0

对于编辑#2下的问题,您可以使用泛型类来使类型在不同的子类中有所不同,尽管它可能会或可能不适用于您,具体取决于您的设计。这可能会导致其他艰难的设计决策。

粗糙例如:

internal abstract class BaseClass 
{ 
    protected object mValue; // could also be defined as a T in BaseClass<T> 

    public object GetColumn4Data { get { return mValue; } } 
} 

// this is a group of classes with varying type 
internal abstract class BaseClass<T> : 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<T> sealed instead of abstract 
internal sealed class BoolSubClass : BaseClass<bool> 
{ 
    // no override necessary so far 
} 

internal sealed class StringSubClass : BaseClass<string> 
{ 
    // no override necessary so far 
} 

但请注意,你不能真正得到这将对某些属性或方法的不同返回类型的单一引用类型。参考文献最多只能返回一般类型(如object)。

+0

不幸的是,这里不行。这种特殊的差异只是几个小但重要的差异之一。如果它是唯一的区别,我会同意这种方法。 – 2012-04-12 00:58:26