在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
中动态创建子控件,但对于较大的控件来说这可能很麻烦。想法?
答案 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,这种方法使控件更容易重复使用,因为它们“自动”告诉您托管控件必须满足的要求。您不必知道您必须以哪种顺序调用控件的哪种方法。