Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用语句并尝试-catch()-最终重复?_C#_Using_Try Catch Finally - Fatal编程技术网

C# 使用语句并尝试-catch()-最终重复?

C# 使用语句并尝试-catch()-最终重复?,c#,using,try-catch-finally,C#,Using,Try Catch Finally,using(…)语句是try{}finally{}的语法糖 但如果我有一个使用语句,如下所示: using (FileStream fs = File.Open(path)) { } 现在,我想捕获打开此文件可能导致的异常(这是一个相当高的风险代码,因为它可能会由于环境而失败),但是如果我在内部编写try-catch,这不是重复吗?当代码被编译成IL时,我假设当代码被JIT时,重复会被删除 但是,我希望捕获打开文件可能导致的异常(因此我应该将try-catch包装在using语句的范围之外

using(…)语句是try{}finally{}的语法糖

但如果我有一个使用语句,如下所示:

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


}
现在,我想捕获打开此文件可能导致的异常(这是一个相当高的风险代码,因为它可能会由于环境而失败),但是如果我在内部编写try-catch,这不是重复吗?当代码被编译成IL时,我假设当代码被JIT时,重复会被删除

但是,我希望捕获打开文件可能导致的异常(因此我应该将try-catch包装在using语句的范围之外),以及在using块内执行的任何操作的异常,以便在块内添加try-catch

这似乎是我在重复CLR内部可能做的事情。CLR是否添加catch子句

我的同事认为using语句很混乱(但这是因为由于我对它们进行了硬编码,所以一行稍长,因为我需要快速更改它们,并且无法访问代码库的其他部分)。上述同事没有使用using语句,但是using语句和try finally/try catch finally之间是否存在功能上的差异?我确实看到过这样的一个案例,其中WCF服务有一个关于使用finally和返回值(关于finally)的不为人知的例子。解决方法是使用检查块。在C#中有类似的东西吗


另一方面,实现IDisposale的所有类型都是非托管资源的所有者吗?与我朋友的讨论表明答案是否定的。(我还阅读了本论坛使用部分的一些帖子,其中有一些非常好的知识)。

如果您需要明确处理声明期间可能发生的不同例外情况,您可以用
try/catch/finally
替换
using
,并在finally中显式调用
Dispose()
。或者您可以使用块在
周围放置一个
try/catch
,将异常情况与确保处置分开

使用
所做的唯一一件事就是确保调用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
}

using和try finally之间最大的区别在于using只调用
Dispose()
方法。如果您实现自己的finally块,则可以执行其他逻辑,例如日志记录,这不会包含在using中。

我的首选是保留using语句并将其包装在try/catch中。外部try/catch将捕获您需要监视的任何异常,同时忽略Dispose()。如果您以后重构它以将try/catch移到其他位置(如在调用函数中),那么这还有一个额外的优点,可以保护您免受攻击


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

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

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

因此,如果您不需要
捕获
,则可以使用
使用
,但如果您需要捕获
,则应使用普通的
尝试/catch/finally
,如果您确实需要处理某些异常,则可以自己实现该模式。就我个人而言,我仍然觉得在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();
    }
}

就我个人而言,我希望看到
使用
扩展到支持
Catch
Finally
块。因为他们已经在代码上执行转换,所以这似乎不会增加那么多额外的复杂性。

try
/
catch
中使用
本身包装
没有什么错。它比
finally
更清晰,因为在块退出后,不必查看
finally
就可以立即看到释放了哪些资源。不过,使用finally支持吗?您是在哪里发现使用匿名作用域块的?我想知道更多关于这方面的情况。因此,当我在using块中打开一个文件(例如filestream.open())时,就会出现这个异常。如果using语句实现了try/finally,我必须将其包装在try/catch中,以获得捕获。