【发布时间】:2017-01-16 15:09:54
【问题描述】:
我注意到我一遍又一遍地重复相同的几行代码,我想重构以防止发生这种情况以进行维护。但是,每次迭代之间的更改都在所有验证的中间,因此我不确定完成此操作的最佳方法。我觉得有一些方法可以编写一个可以接受输入来更改内部代码的通用函数,但我能想到的唯一方法是每个枚举和一个 switch 语句。
有没有更好的方法让这段重复的代码更易读和维护?
在整个过程中重复的特定块:
if (_read.HasRows)
{
while (_read.Read())
{
//DO SOMETHING...;
}
}
_read.Close();
示例用法:
public List<object> TableList()
{
List<object> list = new List<object>();
_cmd.CommandText = "SELECT * FROM sys.tables";
try
{
_read = _cmd.ExecuteReader();
}
catch (Exception e)
{
//please ignore this try catch for now
list[0] = e; //this is a temporary measure until I finalize error handling
}
//block to generalize
if (_read.HasRows)
{
while (_read.Read())
{
list.Add(_read.GetValue(0)); //unique line
}
}
_read.Close();
return list;
}
另一个例子:
private List<object[]> _Columns = new List<object[]>()
private bool SetColumns()
{
_oldCommand = _cmd.CommandText;
_cmd.CommandText = "exec sp_columns " + tableName;
try
{
_read = _cmd.ExecuteReader();
}
catch (Exception e)
{ } //again, ignore the messy error handling. That is coming next.
//block to generalize
if (_read.HasRows)
{
while (_read.Read())
{
_Columns.Add(new object[2] { _read.GetValue(3), _read.GetValue(5) }); //unique line
}
}
_read.Close();
_cmd.CommandText = _oldCommand;
if (_Columns.Count != 0)
{
return true;
}
else
{
return false;
}
}
只是在问题的具体范围底部提醒。 如何概括重复的代码块,同时仍然允许不同用途存在唯一行?我只举了两个例子,但这个问题在整个过程中有几个例子,我想在深入之前进行重构。
看到答案后的最终实现:
/// <summary>
/// Sets a list of tables in the connected database.
/// </summary>
/// <returns>Returns a List<string> of the tables. If there is an error, then the first element of the list will conatin the exception.</returns>
public List<string> TableList()
{
List<string> list = new List<string>();
_cmd.CommandText = "SELECT * FROM sys.tables";
ExecuteReader(_read => { list.Add(_read.GetString(0)); });
_read.Close();
return list;
}
/// <summary>
/// sets column names and types to the _columns private variable [0] = name, [1] = type
/// </summary>
private void SetColumns()
{
_oldCommand = _cmd.CommandText;
_cmd.CommandText = "exec sp_columns " + TableName;
ExecuteReader(_read => columns.Add(new string[2] { _read.GetString(3), _read.GetString(5) }));
_cmd.CommandText = _oldCommand;
_read.Close();
}
/// <summary>
/// Executes the reader with error handling and type returns.
/// </summary>
/// <param name="readline">the code that actually pulls the data from each line of the reader</param>
private void ExecuteReader(Action<SqlDataReader> readline)
{
if (_con.State.HasFlag(ConnectionState.Closed)) { _con.Open(); }
_read = _cmd.ExecuteReader();
while (_read.Read())
{
readline(_read);
}
_con.Close();
}
我选择了这种方法,因为它在我的经验水平上感觉最易读。正如许多其他人所推荐的那样,我已经对 Dapper 进行了一些研究。我很可能会在未来的项目中使用它,因为出于我自己的经验,我喜欢至少编写一次自己的样板代码。
感谢大家的精彩回答。我希望将来其他人会发现这对您有所帮助。
【问题讨论】:
-
您可能想看看Dapper,因为它负责处理与 ADO.Net 相关的大量样板代码。
-
您想将示例 1 与示例 2 统一起来,还是希望将它们中的每一个都概括起来?
-
感谢@stuartd 的评论我通常对验证有点疯狂,不会花时间看看它们是否有必要。像这样的改变正是我试图概括的原因,这样我就可以做出这些改变而不必改变 100 件事。
-
@Ghasan 我想统一这些例子。
if (read_.HasRows)块和其他非常相似的示例重复了太多次。在第三次复制粘贴后,我知道我做错了什么。到目前为止,lamba 表达式的答案是正确的。
标签: c# function lambda refactoring