重构两个非常相似的重载

Refactoring two very similar overloads

我有一个过载:

public DataTable ExecuteStoredProcedure(string storedProcedure)
        {
            var dataTable = new DataTable();
            using (var odbcConnection = _connection)
            {
                using (var odbcCommand = odbcConnection.CreateCommand())
                {
                    odbcCommand.CommandText = storedProcedure;
                    odbcCommand.CommandType = CommandType.StoredProcedure;
                    using (var adapter = new OdbcDataAdapter(odbcCommand))
                    {
                        adapter.Fill(dataTable);
                    }
                }
            }

            return dataTable;
        }

和另一个超载:

    public DataTable ExecuteStoredProcedure(string storedProcedure, List<StoredProcedureParameters> storedProcedureParameters)
    {
        var dataTable = new DataTable();
        using (var odbcConnection = _connection)
        {
            using (var odbcCommand = odbcConnection.CreateCommand())
            {
                odbcCommand.CommandText = storedProcedure;

                foreach (var parameter in storedProcedureParameters)
                {
                    odbcCommand.Parameters.Add("@" + parameter.ParameterName, parameter.ParameterType, 
                        parameter.LengthOfParameter).Value = parameter.ParameterName;
                }

                odbcCommand.CommandType = CommandType.StoredProcedure;
                using (var adapter = new OdbcDataAdapter(odbcCommand))
                {
                    adapter.Fill(dataTable);
                }
            }
        }

        return dataTable;
    }

他们的内容非常相似。事实上如此相似,唯一的区别是这里的这一行:

foreach (var parameter in storedProcedureParameters)
                    {
                        odbcCommand.Parameters.Add("@" + parameter.ParameterName, parameter.ParameterType, 
                            parameter.LengthOfParameter).Value = parameter.ParameterName;
                    }

我花了几个小时试图重构这个人,因为他们是如此相似。我试过委托,但它使代码更难读。我无法组合这两个重载的功能,因为另一个重载逻辑出现在另一个重载的中间。有没有人知道如何将其重构为一种可读的方法?

如果你想运行 foreach 与否,你可以添加一个标志来标记。当然需要更改参数名称,这只是重构的一种可能变体:

public DataTable ExecuteStoredProcedure(string storedProcedure, List<StoredProcedureParameters> storedProcedureParameters, bool withForEach)
    {
        var dataTable = new DataTable();
        using (var odbcConnection = _connection)
        {
            using (var odbcCommand = odbcConnection.CreateCommand())
            {
                odbcCommand.CommandText = storedProcedure;
                if(withForEach)
                foreach (var parameter in storedProcedureParameters)
                {
                    odbcCommand.Parameters.Add("@" + parameter.ParameterName, parameter.ParameterType, 
                        parameter.LengthOfParameter).Value = parameter.ParameterName;
                }

                odbcCommand.CommandType = CommandType.StoredProcedure;
                using (var adapter = new OdbcDataAdapter(odbcCommand))
                {
                    adapter.Fill(dataTable);
                }
            }
        }

        return dataTable;
    }

您可以做几件事:

您始终可以只使用一种方法,但可以使用可选的方法 List<StoredProcedureParameters>

像这样:(为简洁起见,我已将其重命名为 spParams

public DataTable ExecuteStoredProcedure(string storedProcedure,
                                        List<StoredProcedureParameters> spParams
                                                     = new List<StoredProcedureParameters>())
{
    var dataTable = new DataTable();
    using (var odbcConnection = _connection)
    {
        using (var odbcCommand = odbcConnection.CreateCommand())
        {
            odbcCommand.CommandText = storedProcedure;

            foreach (var parameter in spParams)
            {
                odbcCommand.Parameters.Add("@" + parameter.ParameterName, parameter.ParameterType, 
                    parameter.LengthOfParameter).Value = parameter.ParameterName;
            }

            odbcCommand.CommandType = CommandType.StoredProcedure;
            using (var adapter = new OdbcDataAdapter(odbcCommand))
            {
                adapter.Fill(dataTable);
            }
        }
    }

    return dataTable;
}

这样调用同样的方法,选择是否传入List<StoredProcedureParameters>

使用默认值为 spParams= new List<StoredProcedureParameters>() 的参数意味着调用原始 1 参数签名的任何现有代码仍然有效,从而节省额外重构的时间。

另外,这意味着您现有的 foreach 块将只遍历一个空列表。

你可以像上面那样做,只是让 spParams 的值默认为 null,然后做一个 null 检查,像这样:

public DataTable ExecuteStoredProcedure(string storedProcedure,
                                        List<StoredProcedureParameters> spParams = null)
{
    //...

    if (spParams != null) // Check if the spParams is null
    {
        foreach(var param in spParams)
        {
            // Loop in here, if not null
        }
    }

    //...
}

希望对您有所帮助:)

为什么你不能做这样的事情...

public DataTable ExecuteStoredProcedure(string storedProcedure)
{
    return ExecuteStoredProcedure(storedProcedure, null);
}

public DataTable ExecuteStoredProcedure(string storedProcedure, List<StoredProcedureParameters> storedProcedureParameters)
{
    var dataTable = new DataTable();
    using (var odbcConnection = _connection)
    {
        using (var odbcCommand = odbcConnection.CreateCommand())
        {
            odbcCommand.CommandText = storedProcedure;

            if(storedProcedureParameters != null)
            {
                foreach (var parameter in storedProcedureParameters)
                {
                    odbcCommand.Parameters.Add("@" + parameter.ParameterName, parameter.ParameterType, 
                        parameter.LengthOfParameter).Value = parameter.ParameterName;
                }
            }

            odbcCommand.CommandType = CommandType.StoredProcedure;
            using (var adapter = new OdbcDataAdapter(odbcCommand))
            {
                adapter.Fill(dataTable);
            }
        }
    }

    return dataTable;
}

两种方法-

  1. 您可以让第一个方法将空参数列表传递给第二个方法:

    public DataTable ExecuteStoredProcedure(string storedProcedure)
    {
        return ExecuteStoredProcedure(storedProcedure, new List<StoredProcedureParameters>());
    }
    
  2. 您可以从第一种方法传递 null 并在第二种方法中添加 null 检查,如下所示:

    public DataTable ExecuteStoredProcedure(string storedProcedure)
    {
        return ExecuteStoredProcedure(storedProcedure, null);
    }
    

    ...

    if (storedProcedureParameters != null)
    {
            foreach (var parameter in storedProcedureParameters)
            {
                    odbcCommand.Parameters.Add("@" + parameter.ParameterName, parameter.ParameterType, parameter.LengthOfParameter).Value = parameter.ParameterName;
            }
    }