使用Case/Switch和GetType来确定对象[重复]

问题描述 投票:0回答:10

可能重复:
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()

c# .net reflection switch-statement case
10个回答
182
投票

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

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

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

97
投票

如果我真的必须

switch
在对象类型上,我会使用
.ToString()
。然而,我会不惜一切代价避免它:
IDictionary<Type, int>
会做得更好,visitor可能有点矫枉过正,但除此之外它仍然是一个完美的解决方案。


49
投票

在 MSDN 博客文章 许多问题:打开类型 中提供了一些关于为什么 .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; })

35
投票

我面临着同样的问题并发现了这篇文章。 这就是 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;
    }
}

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


32
投票

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

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

另一种方法是:

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

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


21
投票

你可以这样做:

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

它清晰且简单。 它比在某处缓存字典慢一点..但是对于很多代码来说这并不重要..


14
投票

你可以这样做:

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

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


7
投票

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


5
投票

根据您在 switch 语句中所做的操作,正确的答案是多态性。只需在接口/基类中放置一个虚函数并为每个节点类型重写即可。


2
投票

我实际上更喜欢这里给出的答案的方法: 还有比这更好的替代方案来“打开类型”吗?

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

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

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

亲切的问候,韦恩

© www.soinside.com 2019 - 2024. All rights reserved.