web-dev-qa-db-ja.com

Case / SwitchとGetTypeを使用してオブジェクトを決定する

可能性のある複製:
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()をタイプに追加しますか?

136
user29964

Ireallyがオブジェクトのタイプでswitchを必要とする場合、.ToString()を使用します。しかし、私はすべてのコストでそれを避けます:IDictionary<Type, int>ははるかに良くなります、 visitor はやり過ぎかもしれませんが、それ以外の場合はまだ完全に素晴らしい解決策です。

73
Anton Gogolev

独自のユーザー定義型を有効にしたいので、これは問題を直接解決しませんが、組み込み型のみを有効にしたい他の人のために、 TypeCode を使用できます。列挙:

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

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

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; })
41
Arnis Lapsa

Ifステートメントを使用するだけです。この場合:

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

これを行う別の方法は次のとおりです。

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

最初の例は正確な型にのみ当てはまり、後者は継承もチェックします。

24
David Wengier

私は同じ問題に直面していて、この投稿に出会いました。これは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;
    }
}

もしそうなら、私は私が辞書の数字を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;
    }
}

私が見落とした別の実装はありますか?

23
bjaxbjax

あなたはこれを行うことができます:

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

それはもっとエレガントになりますが、ここでの他の答えのいくつかほど効率的ではないかもしれません。

12

あなたはこれを行うことができます:

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

それは明確で簡単です。辞書をどこかにキャッシュするよりも少し遅い..しかし、多くのコードでは、これはとにかく重要ではありません。

9
nreyntje

1つの方法は、純粋な仮想GetNodeType()メソッドをNodeDTOに追加し、それを子孫でオーバーライドして、各子孫が実際の型を返すようにすることです。

7
sharptooth

Switchステートメントで何をしているかに応じて、正しい答えはポリモーフィズムです。インターフェイス/ベースクラスに仮想関数を配置し、各ノードタイプをオーバーライドするだけです。

4
Jason Coyne

私はこれが良いと思う:

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

                            default:
                                    return -1;
                                    break;
                    }
            }
0
Program.X

私は実際にここで答えとして与えられたアプローチを好む: 「スイッチオンタイプ」にこれよりも良い選択肢がありますか?

ただし、C#のようなオブジェクト指向言語に型比較メソッドを実装しないことについては、良い議論があります。代わりに、継承を使用して必要な機能を拡張および追加できます。

この点は、著者のブログのコメントで説明されています: http://blogs.msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535 =

これは非常に興味深い点であり、同様の状況で私のアプローチを変え、他の人に役立つことを願っています。

よろしく、ウェイン

0
Wayne Phipps