9

我有类似于以下的代码。

class MyController
{
    [ThreadStatic] private DbInterface db;

    public void ImportAllData()
    {
        using (db = new DbInterface())
        {
            var records = PullData();
            PushData(records);
        }
    }

    private DbRecord[] PullData()
    {
        return db.GetFromTableA();
    }

    private void PushData(DbRecord[] records)
    {
        db.InsertIntoTableB(records);
    }
}

替代方案维护起来要麻烦得多。

class MyController
{
    public void ImportAllData()
    {
        using (var db = new DbInterface())
        {
            var records = PullData(db);
            PushData(records, db);
        }
    }

    private DbRecord[] PullData(DbInterface db)
    {
        return db.GetFromTableA();
    }

    private void PushData(DbRecord[] records, DbInterface db)
    {
        db.InsertIntoTableB(records);
    }
}

据我所知,我的第一个实现:

  • 是线程安全的(假设DbInterface是线程安全的),
  • 防止任何其他进程接触db变量,并且
  • 即使db在异常期间,也将始终释放 ensure。

using在具有类范围的变量上使用语句是不好的做法吗?我错过了什么吗?

4

4 回答 4

10

就个人而言,我更喜欢你的第二种选择。

第一个设计的问题在于您有效地为设计添加了不必要的耦合。您的PullDataPushData方法不能单独使用 - 它们需要首先调用对设置和正确清理变量的调用ImportAllData或其他方法。db

第二个选项虽然代码稍微多一些(虽然不多),但使每个方法的意图都非常清晰。每个方法都知道它需要处理DbInterface传入它的外部实例。将来被滥用的可能性很小或根本没有。

于 2013-02-12T00:51:59.863 回答
8

您的第一个变体暴露db在由using块管理的范围之外。这打开了意外副作用的可能性。例如,另一种方法可能会使用甚至丢弃 db. 如果您或后来的维护者忘记了隐式合约,db甚至忘记了代码中的拼写错误,这可能会发生。

我不会使用第一个变体。

于 2013-02-12T00:52:02.193 回答
4

这是一个替代方案:

sealed class MyImporter
{
    private readonly DbInterface db;

    public MyImporter(DbInterface db)
    {
        this.db = db;
    }

    public void ImportAllData()
    {
        var records = PullData();
        PushData(records);
    }

    private DbRecord[] PullData()
    {
        return db.GetFromTableA();
    }

    private void PushData(DbRecord[] records)
    {
        db.InsertIntoTableB(records);
    }
}

在这种情况下,保持引用是类责任的一个明确部分。它现在也将处置责任推给了用户。这种更明确的构造减少了向“控制器”添加附加功能的诱惑,这是您的第一种方法从长远来看可能会变坏的原因。本质上,我们将 Import 函数重构为一个单独的类,以便共享字段访问不再是问题。

于 2013-02-12T00:58:47.843 回答
0

这就是构造的用途。我会小心地将 using 放入属性中,因为约定规定属性访问是轻量级的,并且当用户认为他们只是在访问一个变量时,他们不一定想要触发创建 - 处置周期。

然而,下面关于代码结构的注释很重要——如果你想进行一次导入,它就变成了用户需要了解的设置步骤。如果您可以设想不同的访问模式,则依赖注入设置允许用户控制连接的创建和处置。

于 2013-02-12T01:15:04.500 回答