문제

다운캐스트하는 것 외에 기본 클래스 목록을 UI에 바인딩하는 더 좋은 방법이 있습니까?

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;
    }
}
도움이 되었습니까?

해결책

이런 유형의 문제에 직면했을 때 나는 방문자 패턴.

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

따라서 방문자 패턴은 Java, Smalltalk, C#및 C ++와 같은 기존의 단일 디스패치 객체 지향 언어에서 이중 발송을 시뮬레이션합니다.

이 코드의 유일한 장점 jop새로운 유형의 방문자 (예 : xmlserializevisitor 또는 a Feedanimalvisitor).

다른 팁

동물이 돼지와 개가 강제로 구현 해야하는 추상적 인 방법을 포함시키는 이유는 무엇입니까?

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

이런 식으로 각 특정 클래스는 해당 조치에 대한 책임을지고 코드를 더 간단하게 만듭니다. 또한 Foreach 루프 내부에 캐스트 할 필요가 없습니다.

이를 수행하는 또 다른 방법은 메소드를 호출하기 전에 유형 검사를 수행하는 것입니다.

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

당신이 찾고있는 것은 다중 파견입니다.아니요 - C#은 다중 디스패치를 ​​지원하지 않습니다.단일 디스패치만 지원합니다.C#은 수신자의 유형에 따라 메서드를 동적으로 호출할 수만 있습니다(예:의 왼쪽에 있는 개체입니다.메소드 호출에서)

이 코드는 이중 파견.코드 자체를 설명하겠습니다.

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

메모:샘플 코드는 이보다 훨씬 간단합니다.저는 이중 파견을 C# 프로그래밍의 중포 중 하나로 생각합니다. 최후의 수단으로만 사용합니다.그러나 수행해야 할 개체 유형이 많고 바인딩 유형도 많이 다른 경우(예:HTML 페이지에 바인딩해야 하지만 WinForms, 보고서 또는 CSV에도 바인딩해야 합니다. 결국에는 이중 디스패치를 ​​사용하도록 코드를 리팩터링할 것입니다.

당신은 당신의 기본 클래스를 최대한 활용하지 않습니다. 동물 수업에서 개와 돼지가 우선적으로 우선적으로 가상 기능을했을 때 아무것도 캐스팅 할 필요가 없습니다.

보다 구체적인 예가 없다면 ToString ()을 무시하십시오.

공장과 관련된 뷰 클래스를 원한다고 생각합니다.

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

그러면 Dogview와 Pigview는 다음과 같은 모양의 동물 뷰를 상속합니다.

class AnimalView {
  abstract void DoStuff();
}

당신은 다음과 같은 일을하게됩니다.

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

또한 이것이 전략 패턴의 구현이라고 말할 수 있다고 생각합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top