与接口绑定时C#向下转换
时间:2020-03-06 14:51:23 来源:igfitidea点击:
除了向下转换以外,是否有更好的方法将基类列表绑定到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; } }
解决方案
为什么不让Animal包含猪和狗被强制实施的抽象方法
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循环中进行强制转换。
我们没有充分利用基类。如果我们在Animal类中有一个虚拟函数被Dog&Pig覆盖,则不需要进行任何转换。
除非有更具体的示例,否则只需重写ToString()。
另一种方法是在调用方法之前执行类型检查:
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); } }
注意:示例代码比这简单得多。我认为双重派遣是Cprogramming中的重型火炮之一,我只能把它当作不得已而为之。但是,如果我们需要执行许多类型的对象和许多不同类型的绑定操作(例如,我们需要将其绑定到HTML页面,但是还需要将其绑定到WinForms或者报表或者CSV) ,我最终将重构代码以使用双调度。
遇到此类问题时,我会遵循访客模式。
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或者FeedAnimalVisitor)时,可以在不同的类上实现IVisitor接口。
我认为我们想要一个与工厂关联的视图类。
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将继承类似于以下内容的AnimalView:
class AnimalView { abstract void DoStuff(); }
我们最终将执行以下操作:
foreach (animal in list) foreach (entry in factories) if (entry.Key(animal)) entry.Value(animal).DoStuff();
我猜我们也可以说这是策略模式的一种实现。