如何避免重复的代码?

20

我还是编程新手,发现自己在重复代码:

protected void FillTradeSetups()
{
    DBUtil DB = new DBUtil();
    DataTable dtTradeSetups;

    dtTradeSetups = DB.GetTradeSetups();
    ddlSetups.DataValueField = "tradeSetupId";
    ddlSetups.DataSource = dtTradeSetups;
    ddlSetups.DataBind();
}

protected void FillTimeFrames()
{
    DBUtil DB = new DBUtil();
    DataTable dtTimeFrames;

    dtTimeFrames = DB.GetTimeFrames();
    ddlTimeFrames.DataValueField = "tfCode";
    ddlTimeFrames.DataSource = dtTimeFrames;
    ddlTimeFrames.DataBind();
} 

protected void FillTradeGrades()
{
    DBUtil DB = new DBUtil();
    DataTable dtTradeGrades;

    dtTradeGrades = DB.GetTradeGrades();
    ddlTradeGrades.DataValueField = "tradeGrade";
    ddlTradeGrades.DataTextField = "descr";
    ddlTradeGrades.DataSource = dtTradeGrades;
    ddlTradeGrades.DataBind();
}

protected void FillExecutionGrades()
{
    DBUtil DB = new DBUtil();
    DataTable dtExecutionGrades;

    dtExecutionGrades = DB.GetExecutionGrades();
    ddlExecutionGrades.DataValueField = "executionGrade";
    ddlExecutionGrades.DataTextField = "descr";
    ddlExecutionGrades.DataSource = dtExecutionGrades;
    ddlExecutionGrades.DataBind();
} 

我该如何更聪明地处理这个问题?你能帮我重新编写代码,使其不要重复那么多吗?

更新

哇,谢谢大家的回复,我想分享一下我正在考虑实现的内容。我还创建了另一个小工具来删除其他丑陋的重复代码。你觉得这样怎么样?

void FillDropDownList(DropDownList ddl, DataTable dt, string dataValueField, string dataTextField, string defValue)
{
    ddl.DataValueField = dataValueField;
    ddl.DataSource = dt;
    if (!string.IsNullOrEmpty(dataTextField))
    {
        ddl.DataTextField = dataTextField;
    }

    ddl.DataBind();
    ddl.SelectedValue = defValue;
}

private string GetTradeItem(DataTable tradeDetails, string attribute)
{
    return tradeDetails.Rows[0][attribute].ToString();
}

然后使用类似以下的方式调用:

int tradeId = int.Parse(Request.QueryString["tradeId"]);
DBUtil DB = new DBUtil();
DataTable tradeDetails = DB.GetTrade(tradeId);
FillDropDownList(ddlTradeGrades, DB.GetTradeGrades(), "tradeGrade", "descr", GetTradeItem(tradeDetails, "tradeGrade"));

编程感觉很棒,当一些丑陋的东西变成更优雅的东西时。

13
在职业生涯的早期阶段,一个好问题是要问自己:如何避免“片段式”和“复制粘贴编程”,这是一个重要的技能需要掌握。 - user2100815
1
你想阅读《重构》(Refactoring)的内容,请点击链接:http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672。 - John Saunders
被投票关闭为重复问题,但是优秀的回答应该与原问题合并。 - John Saunders
这个问题难道不是关于如何避免重复代码的吗,而不是关于这个具体例子的吗?我必须说,我对这些太具体的答案感到有点失望。 - user2100815
@NeilButterworth:请阅读帖子底部的原始问题。很明显,这是为了学习目的而提供的特定示例。 - mellamokb
显示剩余3条评论
7个回答

8
也许可以像这样做?
void SetupDataSource(DropDownList ddl, DataTable dt, string dataValueFieldm, string dataTextField)
{
    if (ddl != null)
    {
        ddl.DataValueField = dataValueField;
        ddl.DataSource = dt;
        if (!string.IsNullOrEmpty(dataTextField)) 
        {
            ddl.DataTextField  = dataTextField;
        }

        ddl.DataBind();
    }
    else
    {
       throw new ArgumentNullException("ddl");
    }
}

@John 避免 NullReferenceException,但我猜检查的要求是情境性的,有时候不检查更好。 - Bala R
@mellamokb 我刚刚添加了 DataTextField - Bala R
@Bala:我的观点是原始代码没有这个检查,因此可以推断出它不是必需的。 - John Saunders
9
我认为那里的空值检查是“不好的实践”,因为它隐藏了一个编程错误(假定传入的值是“有效”的)。如果有必要的话,应该是 if (ddl == null) throw new ArgumentNullException("ddl");。请注意,这只是翻译,没有解释或添加额外的内容。 - user166390

7

如果有用的话,可以尝试以下内容:

void BindControl(DropDownList ddl, string valueField, string textField, DataTable data) {
    ddl.DataValueField = valueField;
    ddl.DataTextField = textField ?? valueField; // textField can be null
    ddl.DataSource = data;
    ddl.DataBind();
}

DBUtil DB = new DBUtil();
BindControl(ddlTradeGrades, "tradeGrade", "descr", DB.GetTradeGrades());
...

然而,这种管道本身并不是非常重复的,应考虑将来修改/维护的便利性。

愉快的编码。


2
创建一个方法来设置你想要的内容:
void SetValues(DropDownList ddl, string datavalue, string text, object ds)
{
    ddl.DataValueField = dataValue;
    ddl.DataTextField = text;
    ddl.DataSource = ds;
    ddl.DataBind();
}

然后您可以使用以下方式调用它:

SetValues(ddlTradeGrades, "tradeGrade", "descr", dtTradeGrades);

@John:一种类型。不幸的是,这种类型在框架中没有定义。改为使用“Object”以匹配“DropDownList”使用的内容。 - Jim Mischel

2
如何尝试这样的方式:

void FillData(DataTable dataSource, DropDownList ddl, string dataValueField, string dataTextField)
{
    ddl.DataSource = dt;
    ddl.DataValueField = dataValueField;
    ddl.DataTextField = dataTextField;
    ddl.DataBind();
}

那么你可以这样调用它:
FillData(DB.GetTradeSetups(), ddlSetups, "tradeSetupId", string.Empty)

1
你可以像这样做:
   private void BindMyLists()
    {
        DBUtil DB = new DBUtil();
        BindDropDownList(this.ddlExecutionGrades, DB.GetExecutionGrades(), "executionGrade", "descr");
        BindDropDownList(this.ddlTradeGrades, DB.GetTradeGrades(), "tradeGrade", "descr");
        //etc
    }
    protected void BindDropDownList(DropDownList dropDownList, DataTable dataTable, string dataValueField, string dataTextField)
    {
        dropDownList.DataValueField = dataValueField;
        dropDownList.DataTextField = dataTextField;
        dropDownList.DataSource = dataTable;
        dropDownList.DataBind();
    }

BindDropDownList 中,ddlTradeGrades -> dropDownList - mellamokb
哎呀...我提交得太快了,出现了很多错误。应该被踩。已经修改好以供参考。抱歉。 - Jemes

1

可能是这样的...

protected void FillDdl(DropDownList ddl, string dataValueField, Func<DataTable> dataTableMethod)
{
    FillDdl(ddl, dataValueField, null, dataTableMethod);
}

protected void FillDdl(DropDownList ddl, string dataValueField, string dataTextField, Func<DataTable> dataTableMethod)
{
    DataTable dt = dataTableMethod();

    ddl.DataSource = dt;

    ddl.DataValueField = dataValueField;
    ddl.DataTextField = dataTextField ?? dataValueField;

    ddl.DataBind();
}

然后直接像这样调用

DBUtil DB = new DBUtil();

FillDdl(ddlSetups, "tradeSetupId", DB.GetTradeSetups);
FillDdl(ddlTimeFrames, "tfCode", DB.GetTimeFrames);
FillDdl(ddlTradeGrades, "tradeGrade", "descr", DB.GetTradeGrades);
FillDdl(ddlExecutionGrades, "executionGrade", "descr", DB.GetExecutionGrades);

或者你仍然可以拥有瘦小的个体方法

protected void FillTradeSetups()
{
    DBUtil DB = new DBUtil();
    FillDdl(ddlSetups, "tradeSetupId", DB.GetTradeSetups);
}

protected void FillTimeFrames()
{
    DBUtil DB = new DBUtil();
    FillDdl(ddlTimeFrames, "tfCode", DB.GetTimeFrames);
} 

protected void FillTradeGrades()
{
    DBUtil DB = new DBUtil();
    FillDdl(ddlTradeGrades, "tradeGrade", "descr", DB.GetTradeGrades);
}

protected void FillExecutionGrades()
{
    DBUtil DB = new DBUtil();
    FillDdl(ddlExecutionGrades, "executionGrade", "descr", DB.GetExecutionGrades);
} 

+1 但需要注意的是,使用委托可能会触发一些与调试和单元测试相关的CLR(公共语言运行时)模糊错误。在这种情况下,被调用的方法非常简单,实际上并不需要使用委托,因此我建议不要使用委托。如果它们是具有不同签名的方法,或者需要执行的不仅仅是方法调用,则委托将是正确的选择。 - John Saunders
谢谢。那么,在方法中传递一个字符串methodName,然后使用反射(速度较慢且可能过度)或case语句调用DBUtil上的适当方法是否更好? - amit_g
1
最好的做法是只需使用类型为“DataTable”的参数,并在调用者中使用“DB.GetTradeSetups()”、“DB.GetTradeGrades()”等。 - mellamokb
没错,就像 @mellam 说的那样,你不需要使用委托或方法名称提供的完整通用性。 - John Saunders


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接