编辑:下面显示了两个选项。
如果您只是使用 IDisposable 提供的功能,则恰当命名的using
子句可以正常工作。如果您在对象中包装 IDisposable
,则包含对象本身需要是 IDisposable
并且您需要实现适当的模式(要么一个密封的 IDisposable
类,或者更困惑但 standard virtual
pattern )。
但有时辅助工厂方法有利于清洁。如果你在构造后直接返回一个IDisposable
,你可以,但是如果你先构造它然后修改它或者以其他方式执行可以在返回之前抛出异常的代码,你需要安全地调用.Dispose()
- 但仅出现错误时。
例如,不安全的代码可能看起来像这样......
DbCommand CreateCommandUnsafely(string commandText)
{
var newCommand = connection.CreateCommand();
newCommand.CommandText = commandText; //what if this throws?
return newCommand;
}
解决方案 下面是两个安全变体...
DbCommand CreateCommandSafelyA(string commandText)
{
DbCommand newCommand = null;
bool success = false;
try {
newCommand = connection.CreateCommand();
newCommand.CommandText = commandText; //if this throws...
success=true;
return newCommand;
} finally{
if (!success && newCommand != null )
newCommand.Dispose(); //...we'll clean up here.
}
}
DbCommand CreateCommandSafelyB(string commandText)
{
DbCommand newCommand = null;
try {
newCommand = connection.CreateCommand();
newCommand.CommandText = commandText; //if this throws...
return newCommand;
} catch {
if (newCommand != null)
newCommand.Dispose(); //...we'll clean up here.
throw;
}
}
安全变体 A 只长了一行,但似乎是惯用的方法。似乎没有任何真正简洁的解决方案,尽管下面的一些海报提供了一些使用 lambda 的选项来提取封装此逻辑。
上述任何安全方法的代码膨胀仍然存在,并且对于最初看起来像...的代码尤其严重
return new MyDisposableThing {
OptionA = "X",
OptionB = B.Blabla,
Values = src.Values.Where(priority => priority > 1.0),
};
上面安全编写的代码有点长而且可读性差,因为您不能再安全地使用缩短的 setter 语法。
最佳答案
不 - 我认为没有更好的方法。
但是,您可以编写一个辅助类:
public static class DisposeHelper
{
public static TDisposable DisposeOnError<TDisposable>(TDisposable dispoable, Action<TDisposable> action)
where TDisposable : IDisposable
{
try
{
action(dispoable);
}
catch(Exception)
{
disposable.Dispose();
throw;
}
return disposable;
}
}
所以你可以这样写:
return DisposeHelper.DisposeOnError(connection.CreateCommand(), cmd => cmd.CommandText = commandText);
但是,我不确定这是否真的是更好的方法。
关于c# - 安全返回构造的 IDisposables 的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1915352/