使用Case / Switch和GetType来确定对象

时间:2009-04-02 09:07:04

标签: c# .net reflection switch-statement case

  

可能重复:
  C# - Is there a better alternative than this to ‘switch on type’?

如果你想对某种类型的对象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()添加到类型?

11 个答案:

答案 0 :(得分:101)

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

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

    case TypeCode.Int32:
        // Handle Int32
        break;
     ...
}

答案 1 :(得分:71)

如果我真的必须switch对象类型,我会使用.ToString()。但是,我会不惜一切代价避免它:IDictionary<Type, int>会做得更好,visitor可能是一种矫枉过正,但除此之外它仍然是一个非常好的解决方案。

答案 2 :(得分:40)

在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; })

答案 3 :(得分:24)

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

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

另一种方法是:

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

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

答案 4 :(得分:23)

我遇到了同样的问题并且发现了这篇文章。 这是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;
    }
}

我还忽略了另一种实现吗?

答案 5 :(得分:12)

你可以这样做:

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

虽然那会更优雅,但它可能没有其他一些答案那么高效。

答案 6 :(得分:9)

你可以这样做:

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

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

答案 7 :(得分:7)

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

答案 8 :(得分:4)

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

答案 9 :(得分:0)

我在交换机顶部使用字符串(Name):

  private int GetNodeType(NodeDTO node)
            {
                    switch (node.GetType().Name)
                    { 
                            case "CasusNodeDTO":
                                    return 1;
                                    break;
                            case "BucketNodeDTO":
                                    return 3;
                                    break;
                           // ...

                            default:
                                    return -1;
                                    break;
                    }
            }

答案 10 :(得分:0)

我实际上更喜欢这里给出的方法: Is there a better alternative than this to 'switch on type'?

然而,有一个很好的论据是没有在像C#这样的面向对象语言中实现任何类型比较方法。您可以使用继承作为替代扩展并添加额外的必需功能。

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

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

亲切的问候,韦恩