171

可能重复:
C# - 有没有比这更好的选择来“打开类型”?

如果你想switch在一种对象上,最好的方法是什么?

代码片段

private int GetNodeType(NodeDTO node)
{
    switch (node.GetType())
    { 
        case typeof(CasusNodeDTO):
            return 1;
        case typeof(BucketNodeDTO):
            return 3;
        case typeof(BranchNodeDTO):
            return 0;
        case typeof(LeafNodeDTO):
            return 2;
        default:
            return -1;
    }
}

我知道这不起作用,但我想知道你如何解决这个问题。if/else在这种情况下陈述是否合适?

还是您使用开关并添加.ToString()到类型?

4

10 回答 10

156

这不会直接解决您的问题,因为您想打开自己的用户定义类型,但为了其他只想打开内置类型的人的利益,您可以使用TypeCode枚举:

switch (Type.GetTypeCode(node.GetType()))
{
    case TypeCode.Decimal:
        // Handle Decimal
        break;

    case TypeCode.Int32:
        // Handle Int32
        break;
     ...
}
于 2011-02-04T19:41:58.830 回答
92

如果我真的必须switch使用对象类型,我会使用.ToString(). 然而,我会不惜一切代价避免它:IDictionary<Type, int>会做得更好,访问者可能是一个矫枉过正,但否则它仍然是一个完美的解决方案。

于 2009-04-02T09:10:32.327 回答
47

在 MSDN 博客文章Many Questions: switch on type中提供了一些关于为什么.NET不提供开关类型的信息。

像往常一样 - 变通办法总是存在的。

这不是我的,但不幸的是我失去了来源。它使切换类型成为可能,但我个人认为这很尴尬(字典的想法更好):

  public class Switch
  {
      public Switch(Object o)
      {
          Object = o;
      }

      public Object Object { get; private set; }
  }


  /// <summary>
  /// Extensions, because otherwise casing fails on Switch==null
  /// </summary>
  public static class SwitchExtensions
  {
      public static Switch Case<T>(this Switch s, Action<T> a)
            where T : class
      {
          return Case(s, o => true, a, false);
      }

      public static Switch Case<T>(this Switch s, Action<T> a,
           bool fallThrough) where T : class
      {
          return Case(s, o => true, a, fallThrough);
      }

      public static Switch Case<T>(this Switch s,
          Func<T, bool> c, Action<T> a) where T : class
      {
          return Case(s, c, a, false);
      }

      public static Switch Case<T>(this Switch s,
          Func<T, bool> c, Action<T> a, bool fallThrough) where T : class
      {
          if (s == null)
          {
              return null;
          }

          T t = s.Object as T;
          if (t != null)
          {
              if (c(t))
              {
                  a(t);
                  return fallThrough ? s : null;
              }
          }

          return s;
      }
  }

用法:

 new Switch(foo)
     .Case<Fizz>
         (action => { doingSomething = FirstMethodCall(); })
     .Case<Buzz>
         (action => { return false; })
于 2009-09-15T11:36:23.887 回答
30

我面临同样的问题并遇到了这篇文章。这就是 IDictionary 方法的含义:

Dictionary<Type, int> typeDict = new Dictionary<Type, int>
{
    {typeof(int),0},
    {typeof(string),1},
    {typeof(MyClass),2}
};

void Foo(object o)
{
    switch (typeDict[o.GetType()])
    {
        case 0:
            Print("I'm a number.");
            break;
        case 1:
            Print("I'm a text.");
            break;
        case 2:
            Print("I'm classy.");
            break;
        default:
            break;
    }
}

如果是这样,我不能说我喜欢将字典中的数字与案例陈述相协调。

这将是理想的,但字典参考杀死了它:

void FantasyFoo(object o)
{
    switch (typeDict[o.GetType()])
    {
        case typeDict[typeof(int)]:
            Print("I'm a number.");
            break;
        case typeDict[typeof(string)]:
            Print("I'm a text.");
            break;
        case typeDict[typeof(MyClass)]:
            Print("I'm classy.");
            break;
        default:
            break;
    }
}

还有另一个我忽略的实现吗?

于 2009-12-02T20:17:25.687 回答
29

我只会使用 if 语句。在这种情况下:

Type nodeType = node.GetType();
if (nodeType == typeof(CasusNodeDTO))
{
}
else ... 

另一种方法是:

if (node is CasusNodeDTO)
{
}
else ...

第一个示例仅适用于精确类型,后者也检查继承。

于 2009-04-02T09:12:16.970 回答
16

你可以这样做:

function void PrintType(Type t) {
 var t = true;
 new Dictionary<Type, Action>{
   {typeof(bool), () => Console.WriteLine("bool")},
   {typeof(int),  () => Console.WriteLine("int")}
 }[t.GetType()]();
}

这很清楚而且很容易。它比在某处缓存字典要慢一些..但是对于很多代码来说,这无论如何都无关紧要..

于 2010-08-04T00:52:52.080 回答
13

你可以这样做:

if (node is CasusNodeDTO)
{
    ...
}
else if (node is BucketNodeDTO)
{
    ...
}
...

虽然这会更优雅,但它可能不如这里的其他一些答案那么有效。

于 2009-04-02T09:12:33.913 回答
7

一种方法是向 NodeDTO 添加纯虚拟 GetNodeType() 方法并在后代中覆盖它,以便每个后代返回实际类型。

于 2009-04-02T09:13:11.027 回答
5

根据您在 switch 语句中所做的事情,正确的答案是多态性。只需在接口/基类中放置一个虚函数并覆盖每个节点类型。

于 2009-04-02T14:08:20.270 回答
0

我实际上更喜欢这里给出的答案: 有比这更好的选择来“打开类型”吗?

然而,关于在 C# 等面向对象的语言中不实现任何类型比较方法,这是一个很好的论点。作为替代方案,您可以使用继承来扩展和添加额外的必需功能。

这一点在作者博客的评论中讨论过:http: //blogs.msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535

我发现这是一个非常有趣的观点,它改变了我在类似情况下的方法,只希望这对其他人有所帮助。

亲切的问候,韦恩

于 2012-07-06T20:11:21.133 回答