C# 在类级变量上使用using语句是一种不好的做法吗?
我有类似于下面的代码C# 在类级变量上使用using语句是一种不好的做法吗?,c#,scope,using,C#,Scope,Using,我有类似于下面的代码 class MyController { [ThreadStatic] private DbInterface db; public void ImportAllData() { using (db = new DbInterface()) { var records = PullData(); PushData(records); } }
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
对具有类作用域的变量使用
using
语句是一种不好的做法吗?我错过什么了吗?就我个人而言,我更喜欢你的第二个选择
第一种设计的问题在于,您的设计会有效地向设计中添加不必要的耦合。您的PullData
和PushData
方法不能单独使用-它们要求首先调用对ImportAllData
的调用,或者调用将设置并正确清理db
变量的其他方法
第二个选项,虽然代码稍微多一些(虽然不多),但使每个方法的意图都非常清楚。每个方法都知道它需要处理传递给它的外部
DbInterface
实例。将来很少或根本不可能被误用。您的第一个变体将db
暴露在使用
块管理的范围之外。这就增加了意外副作用的可能性。例如,另一种方法可能使用或甚至处置db。如果您或以后的维护人员忘记了db
的隐式契约,或者甚至因为代码输入错误,都可能发生这种情况
我不会使用第一个变体。这里有一个替代方案:
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);
}
}
在这种情况下,保持引用是类责任的一个明确部分。现在,它也将处置责任推给了用户。这种更明确的构造减少了向“控制器”添加额外功能的诱惑,而从长远来看,这正是第一种方法可能失败的原因。本质上,我们已经将导入函数重构为一个单独的类,这样共享字段访问就不再是一个问题。这就是构造的目的。我会小心地将using放入属性中,因为约定规定属性访问是轻量级的,并且当用户认为他们只是在访问变量时,不一定要触发create-dispose循环
但是,下面关于代码结构的注释很重要-如果您想导入一次,它将成为用户需要了解的设置步骤。如果可以设想不同的访问模式,依赖项注入设置允许用户控制连接的创建和处理。是否考虑使用扩展?有趣的是,如果你真的赢了表单绘制代码,OnPaint和Paint事件非常像这样,至少在将ref传递到using块之外。您会收到一个分配给您的图形上下文,它的管理/处理由调用方处理,因此您不会在实际的绘制方法中自行处理它。@DanSaltmer,我计划在其他控制器中使用
DbInterface
类。我希望控制器能够访问所有DbInterface
方法,但我不希望控制器了解彼此的私有方法。据我所知,扩展方法将适用于所有DbInterface
实例。还是我误解了你?@tcarvin,我能理解。谢谢您不需要在静态字段上使用ThreadStatic
?我怀疑第一个变量实际上不是线程安全的;它实际上消除了在类内部进行处理的需要,这也将处理db
的责任转移给了调用方。这可能是一件好事,也可能是坏事,但这是班级责任的变化。如果调用方不知道如何创建db
的实例,此模式将不起作用。