sta*_*ica 17 c# exception-handling system.reflection
根据CLI标准(分区IIA,第19章)和System.Reflection.ExceptionHandlingClauseOptions枚举的MSDN参考页面,有四种不同的异常处理程序块:
鉴于这些简短的解释(引自CLI标准,顺便说一句),这些应该映射到C#,如下所示:
catch (FooException) { … }Catch FooException When booleanExpression)finally { … }catch { … }一个简单的实验表明,这种映射不是.NET的C#编译器真正做的事情:
// using System.Linq;
// using System.Reflection;
static bool IsCatchWithoutTypeSpecificationEmittedAsFaultClause()
{
try
{
return MethodBase
.GetCurrentMethod()
.GetMethodBody()
.ExceptionHandlingClauses
.Any(clause => clause.Flags == ExceptionHandlingClauseOptions.Fault);
}
catch // <-- this is what the above code is inspecting
{
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
此方法返回false.也就是说,catch { … }没有作为故障条款发出.
类似的实验表明,事实上clause.Flags == ExceptionHandlingClauseOptions.Clause,即使没有指定异常类型,也会发出catch子句().
catch { … }确实是一个catch子句,那么fault子句如何与catch子句不同?Dam*_*ver 13
有四种不同的异常处理程序块:
- catch子句:"捕获指定类型的所有对象."
- filter子句:"仅在过滤器成功时输入处理程序".
- 最后条款:"处理所有异常和正常退出."
- fault子句:"处理所有异常,但不能正常退出."
鉴于这些简短的解释(引自CLI标准,顺便说一句),这些应该映射到C#,如下所示:
- 抓住 -
catch (FooException) { … }- 过滤器 - 在C#中不可用(但在VB.NET中
Catch FooException When booleanExpression)- 终于 -
finally { … }- 错误 -
catch { … }
这是你出错的最后一行.再次阅读说明.fault并且finally几乎相同地描述.它们之间的区别在于finally始终输入,而fault只有在控制离开try通道异常时才输入.请注意,这意味着catch块可能已经采取了行动.
如果你用C#写这个:
try {
...
} catch (SpecificException ex) {
...
} catch {
...
}
Run Code Online (Sandbox Code Playgroud)
如果控制离开try通孔a,则无法输入第三个块SpecificException.这就是为什么catch {}不是映射fault.
Han*_*ant 12
.NET异常捎带到操作系统的异常支持上.在Windows上称为结构化异常处理.Unix操作系统有类似的信号.
托管异常是SEH异常的一个非常具体的案例.异常代码是0xe0434f53.最后三个十六进制对拼写"COM",告诉你一些关于.NET开始的方式.
一般而言,程序可能会知道何时引发和处理任何异常,而不仅仅是托管异常.您也可以在MSVC C++编译器中看到这一点.catch(...)子句只捕获C++异常.但是如果使用/ EHa选项进行编译,则会捕获任何异常.包括真正令人讨厌的东西,处理器异常,如访问违规.
该故障子句是CLR的版本,在其相应的区块将执行任何操作系统异常,而不仅仅是管理的.C#和VB.NET语言不支持此功能,它们仅支持托管异常的异常处理.但是其他语言可能,我只知道发出它们的C++/CLI编译器.例如,在其using语句的版本中,称为"堆栈语义".
确实C++/CLI支持它,它毕竟是一种强烈支持从托管代码直接调用本机代码的语言.但是对于C#和VB.NET,它们只能通过pinvoke marshaller或CLR中的COM互操作层运行非托管代码.其中已经建立了一个"捕获所有"的处理程序,可以将非托管异常转换为托管异常.这是获取System.AccessViolationException的机制.
sta*_*ica 10
1.如果
catch { … }确实是一个catch子句,那么错误条款与catch子句有何不同?
C#编译器(至少是.NET附带的编译器)实际上看起来catch { … }像是真的一样编译 catch (object) { … }.这可以通过以下代码显示.
// using System;
// using System.Linq;
// using System.Reflection;
static Type GetCaughtTypeOfCatchClauseWithoutTypeSpecification()
{
try
{
return MethodBase
.GetCurrentMethod()
.GetMethodBody()
.ExceptionHandlingClauses
.Where(clause => clause.Flags == ExceptionHandlingClauseOptions.Clause)
.Select(clause => clause.CatchType)
.Single();
}
catch // <-- this is what the above code is inspecting
{
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
该方法返回typeof(object).
所以,从概念上讲,一个故障处理程序 是 类似于一个catch { … }; 但是,C#编译器从不为该确切的构造生成代码,但假装它是一个catch (object) { … },在概念上它是一个catch子句.因此会释放一个catch子句.
旁注: Jeffrey Richter的书"CLR via C#"有一些相关信息(第472-474页):即CLR允许抛出任何值,而不仅仅是
Exception对象.但是,从CLR版本2开始,非Exception值将自动包装在RuntimeWrappedException对象中.所以C#会转变catch为catch (object)而不是catch (Exception).但是有一个原因:可以告诉CLR不要Exception通过应用[assembly: RuntimeCompatibility(WrapNonExceptionThrows = false)]属性来包装非值.顺便说一句,与C#编译器不同,VB.NET编译器转换
Catch为Catch anonymousVariable As Exception.
2. C#编译器是否曾输出错误条款?
它显然不会发出错误条款catch { … }.但是,Bart de Smet的博客文章"读者挑战 - C#中的错误处理程序"表明C#编译器在某些情况下会产生错误条款.
正如人们所指出的,一般来说C#编译器不会生成错误处理程序.但是,stakx与Bart de Smet的博客文章有关如何让C#编译器生成错误处理程序.
C#确实使用错误处理程序来实现迭代器块内的语句.例如,以下C#代码将导致编译器使用fault子句:
public IEnumerable<string> GetSomeEnumerable()
{
using (Disposable.Empty)
{
yield return DoSomeWork();
}
}
Run Code Online (Sandbox Code Playgroud)
使用dotPeek和"显示编译器生成的代码"选项反编译生成的程序集,可以看到fault子句:
bool IEnumerator.MoveNext()
{
try
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
this.<>7__wrap1 = Disposable.Empty;
this.<>1__state = 1;
this.<>2__current = this.<>4__this.DoSomeWork();
this.<>1__state = 2;
return true;
case 2:
this.<>1__state = 1;
this.<>m__Finally2();
break;
}
return false;
}
__fault
{
this.System.IDisposable.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
通常,using语句将映射到try/finally块,这对迭代器块没有意义 - 在生成第一个值之后,try/finally会Dispose.
但是如果DoSomeWork抛出异常,你确实想要Dispose.所以故障处理程序在这里很有用.它只会在发生异常的情况下调用Dispose,并允许异常冒泡.从概念上讲,这类似于处理然后重新抛出的catch块.
| 归档时间: |
|
| 查看次数: |
2235 次 |
| 最近记录: |