C# 如何使用干式主体重构此代码?

C# 如何使用干式主体重构此代码?,c#,generics,dry,C#,Generics,Dry,我想使用泛型组合两个函数 static public DataTable GetDataTable(SqlParameterHash parameters, string sql, string connectionString, CommandType commandType = CommandType.StoredProcedure) { var da = new SqlDataAdapter(sql, connectionString);

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

    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;
    }
static private T GetDataX(T容器
,SqlParameterHash参数,字符串sql,字符串连接字符串
,CommandType CommandType=CommandType.StoredProcess
)其中T:System.ComponentModel.MarshallByValueComponent,new()
{
var da=新的SqlDataAdapter(sql,connectionString);
da.SelectCommand.CommandType=命令类型;
da.SelectCommand.CommandTimeout=0;
foreach(参数中的SqlParameter参数)
{da.SelectCommand.Parameters.Add(Parameter);}
da.Fill(container);//错误:无法从“T”转换为“System.Data.DataTable”
返回容器;
}
但是我得到了上面显示的错误

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

因为
DataSet
DataTable
是完全独立的类,您必须使用不同的
SqlDataAdapter重载。填充
对于它们中的每一个,您将无法使用通用方法将两个方法简化为一个。但是,您可以使用一种方法来减少重复代码,该方法接受一个委托,该委托定义了在方法过程中如何处理
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;
}
公共静态数据表GetDataSet( SqlParameterHash参数、字符串sql、字符串connectionString、, CommandType CommandType=CommandType.StoredProcess ) { 数据集ds=新数据集(); UseDataAdapter( 参数、sql、connectionString、, da=>da.Fill(ds),commandType ); 返回ds; } 公共静态数据表GetDataTable( SqlParameterHash参数、字符串sql、字符串connectionString、, CommandType CommandType=CommandType.StoredProcess ) { DataTable dt=新的DataTable(); UseDataAdapter( 参数、sql、connectionString、, da=>da.Fill(dt),commandType ); 返回dt; } 公共静态无效UseDataAdapter( SqlParameterHash参数、字符串sql、字符串connectionString、, 动作适配器动作, CommandType CommandType=CommandType.StoredProcess ) { SqlConnection连接=新的SqlConnection(connectionString); connection.Open(); SqlDataAdapter da=新的SqlDataAdapter(sql,连接); da.SelectCommand.CommandType=命令类型; da.SelectCommand.CommandTimeout=0; foreach(参数中的SqlParameter参数) {da.SelectCommand.Parameters.Add(Parameter);} 自适应作用(da); da.SelectCommand.Parameters.Clear(); 返回dt; }
您可以添加一个
操作
参数来填充您想要支持的每种类型:

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 private T GetDataX(SqlParameterHash参数、字符串sql、字符串connectionString、Action fillAction、CommandType CommandType=CommandType.StoredProcess)
其中T:System.ComponentModel.MarshallByValueComponent,new()
{
SqlConnection连接=新的SqlConnection(connectionString);
connection.Open();
SqlDataAdapter da=新的SqlDataAdapter(sql,连接);
da.SelectCommand.CommandType=命令类型;
da.SelectCommand.CommandTimeout=0;
foreach(参数中的SqlParameter参数)
{da.SelectCommand.Parameters.Add(Parameter);}
T容器=新的T();
填充(容器,da);
da.SelectCommand.Parameters.Clear();
返回容器;
}
然后,您可以根据以下方法编写其他方法:

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);
}
静态公共数据表GetDataTable(SqlParameterHash参数,字符串sql, 字符串连接字符串,CommandType CommandType=CommandType.StoredProcess) { 返回GetDataX(参数,sql,connectionString,(dt,adapter)=>{adapter.Fill(dt);},commandType); } 静态公共数据集GetDataSet(SqlParameterHash参数、字符串sql、, 字符串连接字符串,CommandType CommandType=CommandType.StoredProcess) { 返回GetDataX(参数,sql,connectionString,(ds,适配器)=>{adapter.Fill(ds);},commandType); }
强制注释:关闭您的连接。或者更好:甚至不要打开它们,让
da.Fill()
管理它。非常好的建议。我已经编辑了上面的代码,让da.Fill()管理连接。通常我会同意您的意见,但是使用
dynamic
的开销可能会使您的代码慢几个数量级。我认为使用
dynamic
就像用大锤敲钉子一样。