2012-10-11 41 views
-1

我有两个功能,我想结合使用泛型。如何使用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

强制性评论:关闭你的连接。或者更好:甚至不要打开它们,让'da.Fill()'管理它。 –

+0

优秀的建议。我编辑了上面的代码,让da.Fill()管理连接。 – Garfield

回答

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

因为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; 
} 
+0

我很喜欢使用动态因为我喜欢简洁的代码。 – Garfield

+0

通常我会同意你的看法,但使用'dynamic'的开销可能会使你的代码减慢数量级。我认为使用“动态”就像是把大锤钉上钉子。 –