Tri*_*Gao 13 c# language-features design-patterns exception-handling exception
对于需要开始和分离结束部分的情况," 使用 "构造看起来非常方便.
快速举例说明:
using (new Tag("body")) {
Trace.WriteLine("hello!");
}
// ...
class Tag : IDisposable {
String name;
public Tag(String name) {
this.name = name;
Trace.WriteLine("<" + this.name + ">");
Trace.Indent();
}
public void Dispose() {
Trace.Unindent();
Trace.WriteLine("</" + this.name + ">")
}
}
Run Code Online (Sandbox Code Playgroud)
开头部分定义为构造函数,结束部分是Dispose方法.
然而,尽管有吸引力,但这个结构有一个严重的警告,这个警告来自Dispose方法是从finally块中调用的.所以有两个问题:
您应该避免从finally块中抛出异常,因为它们将覆盖应该捕获的原始异常.
如果在"开始"和"结束"之间抛出异常,则无法知道Dispose方法的内部,因此无法相应地处理"结束"部分.
这两件事使得使用这种结构变得不切实际,这是一个非常可悲的事实.现在,我的问题是:
我对问题的理解是对的吗?这是"使用"实际上如何工作?
如果是这样,有没有办法克服这些问题,并实际使用"使用"结构,而不是它最初的设计(释放资源和清理)
如果没有实用的方法来"使用"这种方式.有哪些替代方法(使用开头和结尾部分强制执行某些代码的上下文)?
您的规则#1适用于有或没有using
,所以规则#2是真正的决胜局:选择一个try
/ catch
如果你一定要当一个异常被抛出的情况和正常的程序完成区分.
例如,如果持久层可能在使用数据库连接的过程中发现问题,则无论是否存在异常,您的连接都需要关闭.在这种情况下,using
构造是一个完美的选择.
在某些情况下,您可以using
专门设置以检测正常完成与异常完成.环境交易提供了一个完美的例子:
using(TransactionScope scope = new TransactionScope()) {
// Do something that may throw an exception
scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)
如果在调用之前调用了scope
s ,则知道已抛出异常,并中止事务.Dispose
Complete
TransactionScope
该using
语句和接口的目的IDisposable
是让用户处置非托管资源。这些资源通常是昂贵且珍贵的,因此无论如何都必须处置它们(这就是为什么它出现在 上finally
)。块中的代码finally
甚至无法中止,并且可能会挂起整个应用程序域的关闭。
现在,为了你所描述的目的而滥用是非常诱人的using
,我过去也这样做过。大多数时候那里没有危险。但是,如果发生意外异常,整个处理状态就会受到影响,您不一定要运行结束操作;所以一般来说,不要这样做。
另一种方法是使用 lambda,如下所示:
public interface IScopable {
void EndScope();
}
public class Tag : IScopable {
private string name;
public Tag(string name) {
this.name = name;
Trace.WriteLine("<" + this.name + ">");
Trace.Indent();
}
public void EndScope() {
Trace.Unindent();
Trace.WriteLine("</" + this.name + ">");
}
}
public static class Scoping {
public static void Scope<T>(this T scopable, Action<T> action)
where T : IScopable {
action(scopable);
scopable.EndScope();
}
}
Run Code Online (Sandbox Code Playgroud)
像这样使用它:
new Tag("body").Scope(_ =>
Trace.WriteLine("hello!")
);
Run Code Online (Sandbox Code Playgroud)
您还可以创建其他实现,根据是否引发异常来运行某些操作。
在 Nemerle 中,可以使用新语法来扩展该语言以支持这一点。