23

現在、このコードにいくつかの新しい拡張クラスを追加しています。

foreach (BaseType b in CollectionOfExtendedTypes) {
  if (b is ExtendedType1) {
    ((ExtendedType1) b).foo = this;

  }
  else if (b is ExtendedType2) {
    ((ExtenedType2) b).foo = this;

  } 
  else {
    b.foo = this;

  }
}

isswitch ステートメントでキーワード機能を使用する方法があるかどうかに興味がありましたか?

4

11 に答える 11

36

C# (7) の最新バージョンには、この機能が含まれています。

タイプパターン

型パターンにより、簡潔な型の評価と変換が可能になります。switch ステートメントと共に使用してパターン マッチングを実行すると、式を指定された型に変換できるかどうかがテストされ、変換できる場合はその型の変数にキャストされます。その構文は次のとおりです。

   case type varname 
于 2017-11-30T14:06:29.567 に答える
15

これは、実際には、優れたポリモーフィック実装の状況のように見えます。派生クラスの適切なメソッドをオーバーライドすると、ループ内のチェックがまったく必要なくなる場合があります。

于 2008-10-21T22:06:15.290 に答える
5

いいえ。見る

C# switch ステートメントの制限 - なぜですか?

于 2008-10-21T21:54:46.687 に答える
4

C# では、switch ステートメントの一部として "is" キーワードを使用することはできません。スイッチ内のすべてのケース ラベルは、定数式に評価される必要があります。「is」は定数式に変換できません。

タイプの切り替えに関しては、確かに痛みを感じます。あなたが概説した解決策は実際にはうまくいきますが、xはyを行い、aはbを行うという複雑な言い方です。次のように書く方がはるかに自然です。


TypeSwitch.Do(
    sender,
    TypeSwitch.Case<Button>(() => textBox1.Text = "Hit a Button"),
    TypeSwitch.Case<CheckBox>(x => textBox1.Text = "Checkbox is " + x.Checked),
    TypeSwitch.Default(() => textBox1.Text = "Not sure what is hovered over"));

これは、この機能を実現する方法について書いたブログ投稿です。

http://blogs.msdn.com/jaredpar/archive/2008/05/16/switching-on-types.aspx

于 2008-10-21T21:57:03.920 に答える
2

タイプをチェックするためにswitchステートメントを使用することはできませんが、問題をより管理しやすいコードベースに減らすことは不可能ではありません。

特定の状況と要件に応じて、私は検討します。

  • を使用しIDictionary<Type, T>て結果を辞書に保存します。T自体が、あなたが呼び出すことができる代理人である可能性があります。これは、継承について心配する必要がない場合に機能します。継承のケータリングには、もう少し作業が必要です。

  • switchステートメント内でクラスの型名(文字列)を使用します。これはを使用しswitch (b.GetType().Name)、深い継承構造のオプションはありません。

于 2008-10-21T22:04:58.240 に答える
1

getType()各具象サブクラスによって実装されるメソッドを追加してBaseType、一意の整数ID(おそらく列挙型)を返し、それをオンにすることができます。

于 2008-10-21T21:59:29.047 に答える
1

実際には、switchは変数(stringまたはint(またはenum))をswitchステートメントとしての定数式と一致させます。

http://msdn.microsoft.com/en-us/library/06tc147t(VS.71).aspx

于 2008-10-21T22:01:10.323 に答える
0

私の経験では、型ケースとオブジェクト指向コードはうまく両立していないようです。この状況で私が好むアプローチは、ダブル ディスパッチ パターンです。要するに:

  • ディスパッチする拡張型ごとに、空の仮想メソッド Process(ExtendedTypeN arg) を持つ リスナー型を作成します。
  • リスナーを引数として取る仮想メソッド Dispatch(Listener listener) を基本型に追加します。その実装は、listener.Process((Base) this) を呼び出すことです。
  • 各拡張型で Dispatch メソッドをオーバーライドして、リスナー型で Process の適切なオーバーロード 呼び出します。
  • 関心のある各サブタイプの適切な Process メソッドをオーバーライドして 、リスナー タイプを拡張します。

引数のシャッフル ダンスは、Dispatch の呼び出しに折りたたむことで、ナローイング キャストを排除します。レシーバーは、その正確な型を認識しており、その型に対する Process の正確なオーバーロードをコールバックすることでそれを伝えます。これは、.NET Compact Framework などの実装でのパフォーマンスの大幅な向上でもあります。.NET Compact Framework では、ナローイング キャストは非常に遅くなりますが、仮想ディスパッチは高速です。

結果は次のようになります。


public class Listener
{
    public virtual void Process(Base obj) { }
    public virtual void Process(Derived obj) { }
    public virtual void Process(OtherDerived obj) { }
}

public class Base
{
    public virtual void Dispatch(Listener l) { l.Process(this); }
}

public class Derived
{
    public override void Dispatch(Listener l) { l.Process(this); }
}

public class OtherDerived
{
    public override void Dispatch(Listener l) { l.Process(this); }
}

public class ExampleListener
{
    public override void Process(Derived obj)
    {
        Console.WriteLine("I got a Derived");
    }

    public override void Process(OtherDerived obj)
    {
        Console.WriteLine("I got an OtherDerived");
    }

    public void ProcessCollection(IEnumerable collection)
    {
        foreach (Base obj in collection) obj.Dispatch(this);
    }
}
于 2009-01-16T04:23:47.570 に答える
-1

switchコンパイラがステートメントを処理する方法以外に、考慮すべきことがもう 1 つあります。それは、is演算子の機能です。次の点に大きな違いがあります。

if (obj is Foo)

if (obj.GetType() == typeof(Foo))

名前にもかかわらず、is演算子は、オブジェクトが指定されたタイプであるかどうかではなく、指定されたタイプと互換性があるかどうかを示します。これは、完全に明白ではないバグ (これはかなり明白ですが) につながります。

if (obj is System.Object)
{
   //this will always execute
}
else if (obj is Foo)
{
   //this will never execute
}

ここでの提案の多くは、オブジェクトの型を使用する方向性を示しています。本当に必要なのは、各型に関連付けられたロジックである場合は問題ありません。ただし、その場合は、isオペレーターを使用するときは慎重に歩いてください。

また、これらの基本型を変更することはできませんが、それは Owen の提案を使用できないという意味ではありません。拡張メソッドを実装できます:

public enum MyType { Foo, Bar, Baz };
public static class MyTypeExtension
{
   public static MyType GetMyType(this Foo o)
   {
      return MyType.Foo;
   }
   public static MyType GetMyType(this Bar o)
   {
      return MyType.Bar;
   }
   public static MyType GetMyType(this Baz o)
   {
      return MyType.Baz;
   }
}

次に、ステートメントを使用できます。switch

switch (myObject.GetType())
{
   case MyType.Foo:
     // etc.
于 2008-10-21T22:56:51.117 に答える
-1

C# では、switch ステートメントは整数と文字列でしか機能しないと思います。

于 2008-10-21T21:53:56.767 に答える