首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >处理IDisposable对象

处理IDisposable对象
EN

Code Review用户
提问于 2016-04-19 13:43:20
回答 5查看 725关注 0票数 5

当我大量使用实现IDisposable的对象时,我使用的是这种模式,如这里所示的SqlConnection和SqlCommand。

代码语言:javascript
复制
    private string _connectionString = "";

    public IEnumerable<User> GetUsers()
    {
        List<User> users = new List<User>();
        string sql = "SELECT * FROM [user]";
        InvokeSql(sql, (connection, command) =>
        {
            IDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                User user = new User();
                users.Add(user);

                user.Name = reader["name"] as string;
            }
        });
        return users;
    }

    private void InvokeSql(string sql, Action<SqlConnection, SqlCommand> action)
    {
        if (string.IsNullOrWhiteSpace(sql))
        {
            throw new ArgumentNullException("sql");
        }

        if (action == null)
        {
            throw new ArgumentNullException("action");
        }

        using (SqlConnection connection = new SqlConnection(_connectionString))
        using (SqlCommand command = new SqlCommand(sql, connection))
        {
            connection.Open();
            action(connection, command);
        }
    }

因此,我可以重用InvokeSql,而不必费心处理。但是,在使用语句中使用Action真的是个好主意吗?

EN

回答 5

Code Review用户

发布于 2016-04-19 14:30:57

因此,我可以重用InvokeSql,而不必费心处理。

好的。除了InvokeSqlprivate,所以重用非常局限于该类。如果这个类有一个GetUsers方法,我敢说那个类中只有User-related .而InvokeSql却不是。

很可能,您的模型将不仅仅涉及User实体;我会创建一个基类来封装CRUD和这个InvokeSql方法;然后派生类型可以负责User实体,而另一个派生类型可以负责另一个实体类型--类似于“存储库”。

ExecuteReader返回一个SqlDataReader实例,该实例还实现了IDisposable:这里缺少一个using块:

IDataReader reader = command.ExecuteReader();while (reader.Read())

代码语言:javascript
复制
using (SqlDataReader reader = command.ExecuteReader())
{
    while (reader.Read())
    ...
票数 5
EN

Code Review用户

发布于 2016-04-19 14:49:24

  • 如果您只需要一个Action<SqlConnection, SqlCommand>对象,则不需要有一个SqlCommand参数。
  • 选择所有列仅使用返回的读取器的Name列会减缓整个过程。您应该始终只选择所需的列。
  • 您使用的是C# 6,因此您应该利用nameof表达式,比如if (string.IsNullOrWhiteSpace(sql)) {抛出新的ArgumentNullException(nameof(sql));}但是这个抛出的异常不是正确的,因为如果sql只包含空白,则应该抛出ArgumentException
票数 3
EN

Code Review用户

发布于 2016-04-19 15:11:34

不允许委托具有返回类型,这会使自己的生活变得更加艰难。您可以创建接受Func的重载。

代码语言:javascript
复制
private T InvokeSql<T>(string sql, Func<SqlCommand, T> f)
{
    // same as before but
    return f(command);
}

现在,您可以简化:

代码语言:javascript
复制
public IEnumerable<User> GetUsers()
{
    string sql = "SELECT * FROM [user]";
    return InvokeSql(sql, (command) =>
    {
        var users = new List<User>();
        using (var reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                users.Add(new User
                {
                     Name = reader["name"] as string
                });
        }
        return users;
    });
}

不再需要关闭列表,因为可以直接从委托返回列表。

话虽如此,我还是不喜欢API,因为它不清楚如何参数化SQL。另外,任何参数值都必须关闭.

一般来说,我不喜欢让做错事变得容易的APIs -我认为这是一个很好的例子。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/126113

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档