设置一个支持具有相同基本类型的多个对象的窗体的好方法是什么

本文关键字:类型 对象 窗体 是什么 方法 一个 支持 设置 | 更新日期: 2023-09-27 18:27:50

我有一个基类型(a),它有两个导数(B和C)。基类型不是抽象的。所以,我有三个物体。

B和C之间唯一的区别是它们都有一个额外的不同性质:

  • B.Foo
  • C.酒吧

现在我的代码中有这样的条件:

if(myObject is B)
     myDatabindB.DataSource = ((B)myReport).Foo);
else if(myObject is C)
     myDatabindC.DataSource = ((C)myReport).Bar);

在另一种方法中:

pnlSomePanel.Visible = myObject is B;
pnlSomeOtherPanel.Visible = myObject is C;

但你可以想象,当有一个新的类型时,我必须更新我所有的if-else语句。这违反了许多OO原则。

但问题是,我想不出一个好的、干净的解决方案来解决这个问题。你有解决这个问题的建议/想法吗?

编辑:如果重要的话,我使用MVP模式。

设置一个支持具有相同基本类型的多个对象的窗体的好方法是什么

首先,你只问了三个问题,这很好——这会使解决问题的速度更快:)。您的代码非常通用,所以我只能提供通用的解决方案。

这里的大目标是增加类A、B和C的封装,以确保与A、B或C相关的任何内容都存储在这些类中,而不会移动到其他地方的if语句中。

我们可以将用于确定正确数据源的逻辑从Controller(它正在进行绑定)转移到您的报告中。此方法的名称应该是描述性的,如GetReportSubjectLine()。

class A{
    <snip>
    public virtual SomeDataType getDataSourceForViewType(){
     throw new NotImplementedException()
    }
}
class B{
<snip>
public override SomeDataType getDataSourceForViewType(){
    return this.Foo;
    }
}
class C{
 public override SomeDataType getDataSourceForViewType(){
    return this.Bar;
    }
}

如果您想要制作不同的UI,并且仍然需要报告中的此类信息来生成您正在生成的任何图形视图,则此代码将是可重用的。

你提出的第二个问题没有好办法解决。我们总是可以将面板可见性移动到报告中,但这会大大增加耦合——一个类与另一个类的绑定程度。您的报告不应与特定视图绑定。

最好的解决方案是添加另一层间接——在本例中,是一个中间类,用于处理何时显示哪些面板的逻辑。这样,您的控制器就不必自己承担管理面板可见性的责任。

public class PanelVisibilityManager{
    ICollection<Panel> ManagedPanels {get; set;}
    //
    public IDictionary<System.Type, ICollection<Panel>> Switchboard {get; set;}
    public void TogglePanelsFor(System.Type item){
        foreach(var panel in ManagedPanels){
            panel.Visible=false;
            }
        foreach(var panel in Switchboard[item]){
                 panel.Visible=true;              
            }
}

希望这能有所帮助!

策略模式非常适合第一种情况

对于第二种情况,如果你有面板的一对一映射,你最终可能会得到一个静态只读Dictionary<类型,面板>面板(如果有许多类型)。WinForms中有一个选项卡控件,用于显示某些特定的选项卡以及

避免这种类型代码的方法之一是将决策响应能力转移到对象本身中。例如:

定义A.的收集

List<A> objects = new List<A>{new B(), new C()}

与其让if/else在集合上使用foreach,并在每个对象上调用在a中定义的虚拟方法,并在子对象中覆盖,如

virtual bool ThisIsMe(A objectToCheck){}

B和C通过检查objectToCheck是否为其类型来覆盖此方法,并返回与其相关的truefalse

编辑

示例:

public class A 
{
   public virtual bool ThisIsMe(A objectToCheck){}
   public virtual object GetData{}
}
public class B : A 
{
   public override  bool ThisIsMe(A objectToCheck)
   {   
      return objectToCheck is B;
   }
   public override object GetData()
   {
      return this.Foo;
   }
}
public class C : A 
{
   public override  bool ThisIsMe(A objectToCheck)
   {   
      return objectToCheck is B;
   }
   public override object GetData()
   {
      return this.Bar;
   }
}

现在不是if/else,而是类似这样的东西:

foreach(A objA in objects) { if(objA.ThisIsMe(myObject)) { myDatabindB.DataSource = objA.GetData(); break; } }

也可以用一些花哨的LINQ指令来代替这一点。

希望这能有所帮助。

Dictionary<Type, Action>怎么样?

然后你可以做这样的事情:

var myActors = new Dictionary<Type, Action<BaseClass>>();
myActors.Add(typeof(classA), DoSomethingWithA);
myActors.Add(typeof(classB), DoSomethingWithB);
...
Action actor;
if(myActors.TryGetValue(specialRetrievedOnlyAsBase.GetType(), actor))
{
    ResetEverything();
    actor(specialRetrievedOnlyAsBase);
}
else
{
    // ToDo: What should happen if this type is not supported?
}
...
private void DoSomethingWithA(BaseClass)
{
    var classAObject = (ClassA)BaseClass;
    // ToDo: What should happen if classA arrives?
}
private void DoSomethingWithA(BaseClass)
{
    var classAObject = (ClassB)BaseClass;
    // ToDo: What should happen if classB arrives?
}