如何设计数据库连接类的通用数据读取方法并注入自定义逻辑?
解决方案:用委托或接口封装可变逻辑,复用数据库操作
一、优先选委托:轻量适配单逻辑注入
如果只是需要注入一段数据读取时的处理逻辑(比如填充下拉框、树形视图),委托是最直接的选择,不用额外定义接口或类,代码简洁。
实现步骤:
- 封装数据库连接的创建、打开、关闭通用逻辑
- 给
GetData方法添加委托参数,接收外部自定义处理代码 - 在方法内部执行通用数据库操作,读取数据时调用传入的委托
代码示例(C#):
public enum DbType { SQLite, SqlServer // 可扩展其他数据库类型 } public class DbConnector { private readonly string _connectionString; private readonly DbType _dbType; public DbConnector(string connectionString, DbType dbType) { _connectionString = connectionString; _dbType = dbType; } // 定义委托:参数为IDataReader,适配数据读取后的处理逻辑 public delegate void DataProcessDelegate(IDataReader reader); public void GetData(string sql, DataProcessDelegate processData) { using var connection = CreateConnection(); connection.Open(); using var command = connection.CreateCommand(); command.CommandText = sql; using var reader = command.ExecuteReader(); while (reader.Read()) { // 执行外部传入的自定义处理逻辑 processData(reader); } // using块自动释放连接、命令、读取器,无需手动Close } private IDbConnection CreateConnection() { switch (_dbType) { case DbType.SQLite: return new SQLiteConnection(_connectionString); case DbType.SqlServer: return new SqlConnection(_connectionString); default: throw new NotSupportedException("不支持的数据库类型"); } } }
使用方式:
// 初始化数据库连接类 var dbConnector = new DbConnector("你的连接字符串", DbType.SQLite); // 场景1:填充下拉框 dbConnector.GetData("SELECT Id, Name FROM Categories", reader => { var id = reader.GetInt32(0); var name = reader.GetString(1); comboBox1.Items.Add(new ComboItem(id, name)); }); // 场景2:填充树形视图 dbConnector.GetData("SELECT Id, ParentId, Text FROM TreeNodes", reader => { var node = new TreeNode(reader.GetString(2)) { Tag = reader.GetInt32(0) }; // 根据ParentId匹配父节点的逻辑省略 treeView1.Nodes.Add(node); });
委托方案的注意事项:
- 避免在委托内执行耗时操作:会拉长数据库连接占用时间,可能导致连接池耗尽
- UI操作需注意线程安全:WinForms/WPF中要通过Invoke确保UI操作在主线程执行
- 不要手动关闭
IDataReader或IDbConnection:已由using块自动处理,手动关闭会引发异常
二、接口实现:适合复杂逻辑或多步骤处理
如果自定义逻辑需要多方法配合(比如前置验证、后置清理),可以定义接口让外部实现,注入逻辑。
代码示例:
// 定义数据处理接口 public interface IDataProcessor { void ProcessRow(IDataReader reader); // 可扩展Initialize()、Cleanup()等方法 } // 修改DbConnector的GetData方法 public void GetData(string sql, IDataProcessor processor) { using var connection = CreateConnection(); connection.Open(); using var command = connection.CreateCommand(); command.CommandText = sql; using var reader = command.ExecuteReader(); while (reader.Read()) { processor.ProcessRow(reader); } } // 实现接口:下拉框数据处理器 public class ComboBoxDataProcessor : IDataProcessor { private readonly ComboBox _comboBox; public ComboBoxDataProcessor(ComboBox comboBox) { _comboBox = comboBox; } public void ProcessRow(IDataReader reader) { var id = reader.GetInt32(0); var name = reader.GetString(1); _comboBox.Items.Add(new ComboItem(id, name)); } }
使用方式:
var processor = new ComboBoxDataProcessor(comboBox1); dbConnector.GetData("SELECT Id, Name FROM Categories", processor);
接口方案的优势:
- 逻辑分层清晰,适合复杂处理场景,易扩展
- 处理器可复用,同一逻辑能在多个地方调用
- 便于单元测试:可Mock接口测试数据库类逻辑
三、关于Object object = new Function()方式的问题
这种用匿名类/动态对象封装逻辑的方式,在强类型语言中不推荐:
- 无编译期类型检查,调试困难,易出隐性bug
- 代码可读性差,维护成本高
- 无法利用IDE智能提示,开发效率低
选择建议
- 单一数据处理逻辑场景用委托:代码简洁,开发效率高
- 复杂或需复用的处理逻辑用接口:结构清晰,可维护性强
- 无论哪种方案,都要用
using块自动释放数据库资源,避免手动管理连接/读取器导致的资源泄漏
内容的提问来源于stack exchange,提问作者ElektrischInkorrekt
相关产品推荐
相关产品推荐

