如何从代码中消除这些顺序依赖性

时间:2009-09-23 20:05:20

标签: c# .net vb.net webforms

在ASP.Net Web窗体中,我遇到过创建依赖于订单的代码的情况。作为一种明显的代码味道,我正在寻找解决这个问题的解决方案。

伪代码示例如下:

调用Code :: Page.aspx

protected void Page_Load(...) {
    var control = LoadControl("ControlX.ascx");

    // Ugly since the control's constructor is not used by LoadControl 
    control.SetDependencies(...);
}

控制代码:: ControlX.ascx

public void SetDependencies(...) {
}

protected void Page_Load(...) {
    if (dependencies are null)
        throw Exception();
    else
        ContinueProcessing();
}

LoadControl有两个签名,one used above接受控件类物理位置的字符串,并正确创建子控件。而second signature接受控件类作为类类型,以及构造函数的任何参数,但子控件是创建的,如TRULY Understanding Dynamic Controls中所详述。

那么如何以最干净的方式消除这种顺序依赖呢?我的第一个想法是,如果我在ControlX中动态创建子控件,但对于较大的控件来说这可能很麻烦。想法?

1 个答案:

答案 0 :(得分:3)

(我希望能正确理解问题)你可以像这样反转依赖性:

ControlX.ascx的主机(另一个控件或页面)必须实现某个接口(由ControlX定义)。然后,ControlX可以通过该接口从其主机访问其依赖项。

一个小例子就是:

public interface IControlXHost
{
  // methods, properties that allow ControlX to access its dependencies
  int GetStuff();
}

public partial class ControlX : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        var host = (Parent as IControlXHost) ?? (Page as IControlXHost);
        if (host == null) {
            throw new Exception("ControlX's parent must implement IControlXHost");
        }
        else {
            int number = host.GetStuff();
        }
    }
}

主机(托管ControlX的页面或控件)必须实现该接口,例如:

public partial class Default4 : System.Web.UI.Page, IControlXHost
{
    public int GetStuff() {
       return 33;
    }

    protected void Page_Load(object sender, EventArgs e) {
        var control = LoadControl("ControlX.ascx");    
    }
}

IMO,这种方法使控件更容易重复使用,因为它们“自动”告诉您托管控件必须满足的要求。您不必知道您必须以哪种顺序调用控件的哪种方法。