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

use*_*964 143 .net c# reflection case switch-statement

可能重复:
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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道这不起作用,但我想知道如何解决这个问题.if/else在这种情况下是否适用声明?

或者你使用开关并添加.ToString()到类型?

Ash*_*ley 111

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

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

    case TypeCode.Int32:
        // Handle Int32
        break;
     ...
}
Run Code Online (Sandbox Code Playgroud)

  • 好主意,但似乎不适用于用户定义的类。 (3认同)
  • @splattne不应将“ ...”作为代码的一部分,因为实际上“ ...”不是代码。不过,我可以看到一个论点,以使其更易于阅读。但是缩进...我不知道您怎么称呼它为“修复”,仅因为它就是您现在喜欢的方式。我没有看到有关如何缩进代码的任何StackOverflow准则。仅此问题就有各种各样的样式。 (2认同)

Ant*_*lev 76

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

  • 为什么不努力并给出一个在上述情况下应用 IDictionary 的例子呢? (14认同)

Arn*_*psa 42

在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;
      }
  }
Run Code Online (Sandbox Code Playgroud)

用法:

 new Switch(foo)
     .Case<Fizz>
         (action => { doingSomething = FirstMethodCall(); })
     .Case<Buzz>
         (action => { return false; })
Run Code Online (Sandbox Code Playgroud)

  • 非常酷,虽然这是一个相当昂贵的模式,导致GC相对较长的时间.但仍然非常可读...... (3认同)

bja*_*jax 25

我遇到了同样的问题并且发现了这篇文章.这是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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果是这样,我不能说我喜欢将字典中的数字与case语句进行协调.

这将是理想的,但字典引用会杀死它:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

还有其他我忽略的实现吗?

  • 也许您可以创建一个枚举来代替类型字典中的 int ?这应该可以减轻您的代码中那些烦人的魔法数字的影响。 (4认同)

Dav*_*ier 24

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

Type nodeType = node.GetType();
if (nodeType == typeof(CasusNodeDTO))
{
}
else ... 
Run Code Online (Sandbox Code Playgroud)

另一种方法是:

if (node is CasusNodeDTO)
{
}
else ...
Run Code Online (Sandbox Code Playgroud)

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

  • 第二种类型检查是IS较慢,因为它检查整个类层次结构. (3认同)

Dav*_*nde 12

你可以这样做:

if (node is CasusNodeDTO)
{
    ...
}
else if (node is BucketNodeDTO)
{
    ...
}
...
Run Code Online (Sandbox Code Playgroud)

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


小智 10

你可以这样做:

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

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

  • 任何人都在关注为什么这个被低估了?它怎么样不正确或表现不好? (2认同)
  • 这是一个优雅的解决方案,对大量类型有效,并清楚地传达了作者的意图. (2认同)

sha*_*oth 7

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


Jas*_*yne 5

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