如何使用DRY主体重构此​​代码?

时间:2012-10-11 20:23:48

标签: c# generics dry

我想要使用泛型来组合两个函数。

    static public DataTable GetDataTable(SqlParameterHash parameters, string sql,
        string connectionString, CommandType commandType = CommandType.StoredProcedure)
    {
        var da = new SqlDataAdapter(sql, connectionString);
        da.SelectCommand.CommandType = commandType;
        da.SelectCommand.CommandTimeout = 0;

        foreach (SqlParameter Parameter in parameters)
        { da.SelectCommand.Parameters.Add(Parameter); }

        DataTable dt = new DataTable();
        da.Fill(dt);
        return dt;
    }

    static public DataSet GetDataSet(SqlParameterHash parameters, string sql,
        string connectionString, CommandType commandType = CommandType.StoredProcedure)
    {
        var da = new SqlDataAdapter(sql, connectionString);
        da.SelectCommand.CommandType = commandType;
        da.SelectCommand.CommandTimeout = 0;

        foreach (SqlParameter Parameter in parameters)
        { da.SelectCommand.Parameters.Add(Parameter); }

        DataSet ds = new DataSet();
        da.Fill(ds);
        return ds;
    }

这就是我提出的:

    static private T GetDataX<T>(T container
        , SqlParameterHash parameters, string sql, string connectionString
        , CommandType commandType = CommandType.StoredProcedure
        ) where T : System.ComponentModel.MarshalByValueComponent, new()
    {
        var da = new SqlDataAdapter(sql, connectionString);
        da.SelectCommand.CommandType = commandType;
        da.SelectCommand.CommandTimeout = 0;

        foreach (SqlParameter Parameter in parameters)
        { da.SelectCommand.Parameters.Add(Parameter); }

        da.Fill(container); // ERROR: cannot convert from 'T' to 'System.Data.DataTable'
        return container;
    }

但我得到上面显示的错误。

如果我将容器更改为动态,则会编译。但这似乎是一个黑客。 组合这两个函数的正确方法是什么?

2 个答案:

答案 0 :(得分:3)

您可以添加Action参数来为您要支持的每种类型执行填充:

static private T GetDataX<T>(SqlParameterHash parameters, string sql, string connectionString, Action<T, SqlDataAdapter> fillAction, CommandType commandType = CommandType.StoredProcedure) 
    where T : System.ComponentModel.MarshalByValueComponent, new()
{
    SqlConnection connection = new SqlConnection(connectionString);
    connection.Open();

    SqlDataAdapter da = new SqlDataAdapter(sql, connection);
    da.SelectCommand.CommandType = commandType;
    da.SelectCommand.CommandTimeout = 0;

    foreach (SqlParameter Parameter in parameters)
    { da.SelectCommand.Parameters.Add(Parameter); }

    T container = new T();
    fillAction(container, da);
    da.SelectCommand.Parameters.Clear();
    return container;
}

然后你可以用这个方法编写你的其他方法:

static public DataTable GetDataTable(SqlParameterHash parameters, string sql,
        string connectionString, CommandType commandType = CommandType.StoredProcedure)
{
    return GetDataX<DataTable>(parameters, sql, connectionString, (dt, adapter) => { adapter.Fill(dt); }, commandType);
}

static public DataSet GetDataSet(SqlParameterHash parameters, string sql,
        string connectionString, CommandType commandType = CommandType.StoredProcedure)
{
    return GetDataX<DataSet>(parameters, sql, connectionString, (ds, adapter) => { adapter.Fill(ds); }, commandType);
}

答案 1 :(得分:1)

由于DataSetDataTable是完全独立的类,并且您必须为每个类使用不同的SqlDataAdapter.Fill重载,因此您将无法使用将两种方法简化为一种的通用方法。但是,您可以使用一种方法来减少重复代码,该方法接受一个委托,该委托定义在方法过程中如何处理SqlDataAdapter

public static DataTable GetDataSet(
    SqlParameterHash parameters, string sql, string connectionString,
    CommandType commandType = CommandType.StoredProcedure
)
{
    DataSet ds = new DataSet();
    UseDataAdapter(
       parameters, sql, connectionString,
       da => da.Fill(ds), commandType
    );
    return ds;
}

public static DataTable GetDataTable(
    SqlParameterHash parameters, string sql, string connectionString,
    CommandType commandType = CommandType.StoredProcedure
)
{
    DataTable dt = new DataTable();
    UseDataAdapter(
       parameters, sql, connectionString,
       da => da.Fill(dt), commandType
    );
    return dt;
}

public static void UseDataAdapter(
    SqlParameterHash parameters, string sql, string connectionString,
    Action<SqlDataAdapter> adapterAction,
    CommandType commandType = CommandType.StoredProcedure
)
{
    SqlConnection connection = new SqlConnection(connectionString);
    connection.Open();

    SqlDataAdapter da = new SqlDataAdapter(sql, connection);
    da.SelectCommand.CommandType = commandType;
    da.SelectCommand.CommandTimeout = 0;

    foreach (SqlParameter Parameter in parameters)
    { da.SelectCommand.Parameters.Add(Parameter); }

    adapterAction(da);

    da.SelectCommand.Parameters.Clear();
    return dt;
}