2009-09-02 32 views
15

using(...)语句是try {} finally {}的语法糖。使用语句和try-catch() - 最终重复?

但是,如果我再有一个using语句象下面这样:

using (FileStream fs = File.Open(path)) 
{ 


} 

现在我想赶上那打开此文件可能会导致异常(这是相当高的风险代码,它可能因失败环境),但如果我写try-catch内部会不会重复?当代码被编译为IL时,我假设代码被打乱时重复会被删除?但是,我想要捕捉异常打开文件可能会导致(所以我应该包装在使用语句的范围之外的try-catch),以及我在使用块内部做的任何异常,所以我应该添加块内的try-catch。

这看起来好像我为CLR可能在里面做了很多重复。 CLR是否添加catch子句?

我的同事争辩说使用语句很混乱(但这是因为一行代码稍微长一点,因为我编写代码很困难,因为我需要快速更改代码,并且无法访问代码的其他部分基础)。所述同事不使用使用语句,但在使用语句和try-finally/try-catch-finally之间是否存在任何功能差异?我曾看到过这种情况,WCF服务有一个关于最终使用和返回值(最终有关)的不为人知的案例。解决方案是使用一个校验块。在C#中有这样的东西吗?

在另一个说明中,是否实现了非托管资源的IDisposale所有者的所有类型?与朋友的讨论指出了否定的答案。 (我也在这个论坛的使用部分阅读了一些主题,那里有一些非常好的知识)。

回答

7

如果您确实需要处理某些异常,您可以自己实施该模式。就我个人而言,我仍然觉得它更简单(更重要的是,更清晰),只是将使用包装在try/catch块中。

但是,如果你自己做,确保你做对了。 Using块也会创建一个匿名范围块,以便您的变量能够尽早获得收集资格。在Using块末尾调用的.Dispose()方法只会清理非托管资源,因此您的对象所拥有的任何内存可能会稍长一点。这不太可能是一个大问题,但值得记住以防万一。

所以,做模式的一种直接适应,你的代码需要看起来更像是这样的:

{ 
    FileStream fs; 
    try 
    { 
     fs = File.Open(path); 

    } 
    catch (FileNotFoundException e) { /* ... */ } 
    catch (IOException e) { /* ... */ } 
    catch (Exception e) {/* ... */} 
    finally 
    { 
     if (fs != null) fs.Dispose(); 
    } 
} 

就个人而言,我希望看到Using扩展,以支持CatchFinally块。由于他们已经对代码进行了转换,似乎并不会增加额外的复杂性。

+0

尽管最终使用支持吗?你在哪里发现了使用匿名范围块的使用方法?我想更多地了解这一点。所以当我在一个使用块(例如FileSream.Open())中打开一个文件时,这个异常就会冒泡。如果using语句实现try/finally,那么我必须在try/catch中包装它才能获得该catch。 – dotnetdev 2009-10-08 22:44:03

4

如果您需要明确处理在声明中可能发生的不同例外情况,您可以用try/catch/finally代替using,并在终端中明确呼叫Dispose()。或者您可以在using区块周围放置一个try/catch以区分特殊情况和确保处置。

only thing using确保即使在块内引发异常,也会调用Dispose()。这是一般的try/[catch]/finally结构的非常有限的,高度具体的实现。

重要的是,这些选项都没有任何实际影响 - 只要它满足您的需求,可读性和可理解性,谁关心?这不是一个额外的尝试将是一个瓶颈或任何东西!

要回答您的最后一个问题 - 不,IDisposable绝对不一定意味着实施人员已处理非托管资源。这是一个比这更简单,更通用的模式。这里有一个有用的例子:

public class Timer : IDisposable 
{ 
    internal Stopwatch _stopwatch; 
    public Timer() 
    { 
     this._stopwatch = new Stopwatch(); 
     this._stopwatch.Start(); 
    } 

    public void Dispose() 
    { 
     this._stopwatch.Stop(); 
    } 
} 

我们可以利用这个时间的事情,而无需显式依赖于启动和停止使用被称为:

using(Timer timer = new Timer()) 
{ 
    //do stuff 
} 
4

使用和尝试,终于之间最大的区别是该使用只会调用Dispose()方法。如果你实现自己的finally块,可以做其他逻辑,例如日志记录,这将不会包含在使用中。

+0

+1 for shortness – 2012-06-01 12:50:17

7

我希望保留使用语句并将其包装在try/catch中。外部try/catch将捕获需要注意的异常,同时忽略Dispose()。如果稍后将try/catch移动到其他地方(如在调用函数中),则可以保护您免受自己的攻击。

至于你关于IDisposable的问题:任何人都可以因为他们喜欢的任何原因来实现它。没有技术理由将其限制在非托管资源上。 (是否它应该被限制在的非托管资源你的代码是一个不同的问题)。

3

using构造是try/finally块的简写。也就是说,编译器生成:

FileStream fs = null; 
try 
{ 
    fs = File.Open(path); 
    // ... 
} 
finally 
{ 
    if (fs != null) 
     fs.Dispose(); 
} 

因此,它是适当的使用using如果你不需要catch,但如果这样做,那么你应该只使用一个正常try/catch/finally

+2

在'try' /'catch'中使用''本身并没有什么错误。它比'finally'更清晰,因为立即明白在block退出后释放哪些资源,而不必看'finally'。 – 2009-09-02 21:03:22