Frage

Gibt es einen besseren Weg, um eine Liste der Basisklasse auf einem UI andere als einziehe der Bindung z:

static void Main(string[] args) {
    List<Animal> list = new List<Animal>();  
    Pig p = new Pig(5);  
    Dog d = new Dog("/images/dog1.jpg");  
    list.Add(p);  
    list.Add(d);  
    foreach (Animal a in list)   
    {  
        DoPigStuff(a as Pig);  
        DoDogStuff(a as Dog);  
    }  

}  


static void DoPigStuff(Pig p)
{
    if (p != null) 
    {  
        label1.Text = String.Format("The pigs tail is {0}", p.TailLength);
    }  
}

static void DoDogStuff(Dog d) {
    if (d != null) 
    {
        Image1.src = d.Image;
    }
}

class Animal {
    public String Name { get; set; }
}

class Pig : Animal{
    public int TailLength { get; set; }

    public Pig(int tailLength) 
    {
        Name = "Mr Pig";
        TailLength = tailLength;
    }
}

class Dog : Animal {
    public String Image { get; set; }

    public Dog(String image) 
    {
        Name = "Mr Dog";
        Image = image;
    }
}
War es hilfreich?

Lösung

Wenn Sie mit dieser Art von Problem konfrontiert, folge ich dem Besuchermuster .

interface IVisitor
{
  void DoPigStuff(Piggy p);
  void DoDogStuff(Doggy d);
}

class GuiVisitor : IVisitor
{
  void DoPigStuff(Piggy p)
  {
    label1.Text = String.Format("The pigs tail is {0}", p.TailLength);
  }

  void DoDogStuff(Doggy d)
  {
    Image1.src = d.Image;
  }
}

abstract class Animal
{
    public String Name { get; set; }
    public abstract void Visit(IVisitor visitor);
}

class Piggy : Animal
{
    public int TailLength { get; set; }

    public Piggy(int tailLength) 
    {
        Name = "Mr Pig";
        TailLength = tailLength;
    }

    public void Visit(IVisitor visitor)
    {
       visitor.DoPigStuff(this);
    }
}

class Doggy : Animal 
{
   public String Image { get; set; }

   public Doggy(String image) 
   {
     Name = "Mr Dog";
     Image = image;
   }

   public void Visit(IVisitor visitor)
   {
     visitor.DoDogStuff(this);
   }
}

public class AnimalProgram
{
  static void Main(string[] args) {
    List<Animal> list = new List<Animal>();  
    Pig p = new Pig(5);  
    Dog d = new Dog("/images/dog1.jpg");  
    list.Add(p);  
    list.Add(d);

    IVisitor visitor = new GuiVisitor();  
    foreach (Animal a in list)   
    {
      a.Visit(visitor);
    }  
  }
}

Damit das Besuchermuster simuliert Doppel Versendung in einer herkömmlichen Single-Dispatch-objektorientierten Sprache wie Java, Smalltalk, C # und C ++.

Der einzige Vorteil dieses Codes über jop ‘ s ist, dass der IVisitor Schnittstelle kann später auf einer andere Klasse implementiert werden, wenn Sie eine neue Art von Besucher hinzuzufügen (wie eine XmlSerializeVisitor oder FeedAnimalVisitor ).

Andere Tipps

Warum nicht Tier umfasst eine abstrakte Methode, das Schwein und Hund gezwungen sind, zu implementieren

public class Animal
{
    public abstract void DoStuff();
}

public Dog : Animal
{
    public override void DoStuff()
    {
        // Do dog specific stuff here
    }
}

public Pig : Animal
{
    public override void DoStuff()
    {
        // Do pig specific stuff here
    }
}

Auf diese Weise jede spezifische Klasse Verantwortung für ihr Handeln übernimmt, Ihr Code einfacher zu machen. Sie werden auch nicht in Ihrer foreach-Schleife müssen werfen.

Eine andere Möglichkeit, dies zu tun, ist eine typecheck auszuführen, bevor die Methode aufrufen:

if (animal is Pig) DoPigStuff();
if (animal is Dog) DoDogStuff();

Was Sie suchen ist Multiple-Versand. NO - C # unterstützt nicht Multiple-Versand. Es unterstützt nur Single-Versand. C # kann nur dynamisch eine Methode aufrufen, basierend auf dem Typ des Empfängers (d.h. das Objekt auf der linken Seite des. In dem Methodenaufruf)

Dieser Code verwendet double-Versand . Ich werde den Code für sich selbst sprechen lassen:

class DoubleDispatchSample
{
    static void Main(string[]args)
    {
        List<Animal> list = new List<Animal>();
        Pig p = new Pig(5);
        Dog d = new Dog(@"/images/dog1.jpg");
        list.Add(p);
        list.Add(d);

        Binder binder = new Binder(); // the class that knows how databinding works

        foreach (Animal a in list)
        {
            a.BindoTo(binder); // initiate the binding
        }
    }
}

class Binder
{
    public void DoPigStuff(Pig p)
    {
        label1.Text = String.Format("The pigs tail is {0}", p.TailLength);
    }

    public void DoDogStuff(Dog d)
    {
        Image1.src = d.Image;
    }
}

internal abstract class Animal
{
    public String Name
    {
        get;
        set;
    }

    protected abstract void BindTo(Binder binder);
}

internal class Pig : Animal
{
    public int TailLength
    {
        get;
        set;
    }

    public Pig(int tailLength)
    {
        Name = "Mr Pig";
        TailLength = tailLength;
    }

    protected override void BindTo(Binder binder)
    {
        // Pig knows that it's a pig - so call the appropriate method.
        binder.DoPigStuff(this);
    }
}

internal class Dog : Animal
{
    public String Image
    {
        get;
        set;
    }

    public Dog(String image)
    {
        Name = "Mr Dog";
        Image = image;
    }

    protected override void BindTo(Binder binder)
    {
        // Pig knows that it's a pig - so call the appropriate method.
        binder.DoDogStuff(this);
    }
}

Hinweis: Ihr Beispielcode ist viel einfacher als diese. Ich denke an Doppel Versand als eine der schweren Artillerie in C # -Programmierung - Ich kann es nur nehmen als letzten Ausweg. Aber wenn es eine Menge von Arten von Objekten und viele verschiedene Arten von Bindungen sind, die Sie tun müssen, um (zB Sie müssen es zu einer HTML-Seite binden, aber Sie müssen auch an einen WinForms binden oder einen Bericht oder eine CSV) , würde ich meinen Code schließlich Refactoring Doppel Versand zu verwenden.

Sie nehmen nicht den vollen Nutzen aus Ihrer Basisklasse. Wenn Sie eine virtuelle Funktion in der Klasse Tier hatte die Dog & Pig überschreiben, würden Sie nichts werfen müssen.

Wenn Sie ein spezifischeres Beispiel haben nur überschreiben ToString ().

Ich glaube, Sie einen Blick-Klasse mit einer Fabrik verknüpft werden soll.

Dictionary<Func<Animal, bool>, Func<Animal, AnimalView>> factories;
factories.Add(item => item is Dog, item => new DogView(item as Dog));
factories.Add(item => item is Pig, item => new PigView(item as Pig));

Dann wird Ihr DogView und PigView wird AnimalView erben, die so etwas wie folgt aussieht:

class AnimalView {
  abstract void DoStuff();
}

Sie werden etwas zu tun, wie am Ende:

foreach (animal in list)
  foreach (entry in factories)
    if (entry.Key(animal)) entry.Value(animal).DoStuff();

Ich denke, man könnte auch sagen, dass dies eine Umsetzung des Strategie-Musters ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top