Frage

Ich füge noch ein paar neue erweiterten Klassen zu diesem Code:

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;

  }
}

und war neugierig, ob es einen Weg gibt, die is Keyword-Funktionalität in einer switch-Anweisung zu benutzen?

War es hilfreich?

Lösung

Das sieht wirklich wie eine Situation für eine gute polymorphe Implementierung. Wenn Sie die entsprechenden Methoden in den abgeleiteten Klassen überschrieben werden, können Sie nicht die Kontrollen in der Schleife müssen überhaupt.

Andere Tipps

Die neueste Version von C # (7) nun diese Funktionalität

Typ Muster

Der Typ Muster ermöglicht präzise Art Auswertung und Umsetzung. Wenn sie mit dem Switch-Anweisung verwendet Musterabgleich durchzuführen, überprüft es, ob ein Ausdruck kann auf einen bestimmten Typ und umgewandelt werden, wenn es sein kann, wirft es auf eine Variable dieses Typs. Die Syntax ist:

   case type varname 

In C # ist es nicht möglich, das „ist“ Schlüsselwort als Teil einer switch-Anweisung zu verwenden. Alle Fälle Etikett in einem Schalter muss auf konstante Ausdrücke auswerten. „Ist“ nicht konvertierbar auf einen konstanten Ausdruck.

ich auf jeden Fall den Schmerz fühlen, obwohl, wenn es um Einschalten Arten kommt. Weil wirklich die Lösung, die Sie Werke skizziert, aber es ist ein conveluted Weg für x zu sagen, tun y und ein do b. Es wäre viel mehr natular es zu schreiben mehr wie die folgende


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"));

Hier ist eine Blog-Post schrieb ich darüber, wie diese Funktionalität zu erreichen.

http: //blogs.msdn .com / JaredPar / Archiv / 2008/05/16 / Schalt-on-types.aspx

Während es nicht möglich ist, switch-Anweisung zu verwenden Typen zur Überprüfung, ist es nicht unmöglich ist, das Problem auf eine überschaubare Code-Basis zu reduzieren.

Abhängig von der jeweiligen Situation und Anforderung ich in Betracht ziehen würde.

  • ein IDictionary<Type, T> Mit dem Ergebnis in einem Wörterbuch zu speichern. T könnte sich ein Delegierter, die Sie anrufen können. Das funktioniert, wenn Sie brauchen, um über die Vererbung keine Sorge -. Catering für die Vererbung ein wenig mehr Arbeit nehmen

  • Mit dem Typnamen der Klasse in der Switch-Anweisung (die Zeichenkette). Dies verwendet switch (b.GetType().Name) und es gibt keine Möglichkeit für tiefe Vererbungsstruktur.

In C #, glaube ich, die switch-Anweisung nur mit ganzen Zahlen und Strings funktioniert.

Typ-Fälle und objektorientierter Code scheinen nicht auf der gut zusammen in meiner Erfahrung zu bekommen. Der Ansatz, den ich in dieser Situation lieber ist die Double-Dispatch Muster . Kurz gesagt:

  • Erstellen Sie einen Hörer Typ mit einem leeren virtuellen Methode Prozess (ExtendedTypeN arg) für jeden erweiterten Typ wird Dispatching Sie über.
  • Fügen Sie eine virtuelle Methode Dispatch (Listener Listener) zur Basistyp, der einen Hörer als Argument verwendet. Seine Umsetzung wird listener.Process nennen ((Basis) dieses).
  • über Fahrt die Versandart in jedem erweiterten Typ ruft die entsprechende über Last Prozess im Hörer-Typ.
  • Erweitere Hörer Typ durch die entsprechende Prozess Methode überschrieben für jeden Subtyp Sie interessiert sind.

Das Argument Tanz schlurfenden eliminiert die durch sie in den Aufruf von Dispatch-Falten wirft Verengung - der Empfänger weiß, seine genaue Art und kommuniziert es durch den Aufruf der genaue Überlastung des Prozesses für seine Art zurück. Dies ist auch eine große Leistung Sieg in Implementierungen wie .NET Compact Framework, in der Verengung Abgüsse sind extrem langsam, aber virtuelle Versand ist schnell.

Das Ergebnis wird in etwa so sein:


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

Es ist eine andere Sache über neben der Art und Weise zu denken, dass der Compiler switch Aussagen behandelt, und das ist das Funktionieren des is Betreiber. Es gibt einen großen Unterschied zwischen:

if (obj is Foo)

und

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

Trotz des Namens der is Operator Ihnen sagt, ob ein Objekt ist kompatibel mit einem bestimmten Typ, nicht, wenn es ist des angegebenen Typs. Dies führt zu einer nicht-ganz offensichtliche Fehler (obwohl dies ein ziemlich offensichtlich), die wie folgt aussehen:

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

Viele der Vorschläge hier zeigen Sie in Richtung der Typ des Objekts. Das ist in Ordnung, wenn, was Sie wirklich wollen, ist die Logik mit jeder Art verbunden. Aber wenn das der Fall ist, vorsichtig gehen, wenn der is Operator.

Außerdem: wenn Sie diese Basistypen nicht ändern können, das bedeutet nicht, dass Sie nicht Owen Vorschlag verwenden können. Sie könnten Erweiterungsmethoden implementieren:

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

Dann Sie können eine switch Anweisung:

switch (myObject.GetType())
{
   case MyType.Foo:
     // etc.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top