6
社区成员
发帖
与我相关
我的任务
分享您正在准备以 C# 编程为重点的面试吗?初学者和高级面试中经常出现的一个领域是异常处理。C# 中的异常处理在使应用程序健壮可靠方面发挥着重要作用。
掌握异常处理可以让你在面试过程中获得显着优势。为了帮助您在面试中自信地解决这个主题,我们整理了一份全面的异常处理 C# 面试问题和答案列表,深入探讨了该主题的各个方面。
ExceptionC# 中的类和类之间的主要区别SystemException在于它们的用法和目的。以下是主要区别:
Exception类SystemException都是 C# 中异常处理层次结构的一部分。该类Exception充当所有异常的基类,而它SystemException是从该类继承的派生类Exception。Exception用作定义特定于应用程序的自定义异常类的基类。另一方面,该类SystemException用作 CLR(公共语言运行时)和核心 .NET Framework 库引发的异常的基类。Exception:提供通用基类,用于处理异常并创建与应用程序域相关的自定义异常类。SystemException:表示运行时错误或特定于系统和.NET Framework 的错误。这些错误通常表明 CLR 或核心 .NET Framework 库之一存在问题。总之,该类Exception是所有异常的主要基类,而该类SystemException用于处理 CLR 和 .NET Framework 库引发的系统特定异常。
要创建继承自 的自定义异常类ApplicationException,请按照下列步骤操作:
ApplicationException。下面是一个继承自 的自定义异常类的示例ApplicationException:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">CustomException</span> <span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">ApplicationException</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-name-color)">CustomException</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-name-color)">CustomException</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-text-color)">message</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">base</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">message</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-name-color)">CustomException</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-text-color)">message</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">innerException</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">base</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">message</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">innerException</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
但是,必须注意的是,直接派生自定义异常ApplicationException在现代 C# 中并不被认为是最佳实践。相反,建议直接从Exception类继承自定义异常。
下面是一个自定义异常类的示例,它遵循最佳实践并继承自Exception:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">CustomException</span> <span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">Exception</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-name-color)">CustomException</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-name-color)">CustomException</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-text-color)">message</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">base</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">message</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-name-color)">CustomException</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-text-color)">message</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">innerException</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">base</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">message</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">innerException</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
从类继承自定义异常的最佳实践Exception允许更清晰的层次结构,同时保持代码的可读性和一致性。
在 C# 中重新抛出异常时,必须了解使用throw和throw ex保留原始异常信息和堆栈跟踪之间的区别。
throw:当您在throw不指定异常对象的情况下使用时,将重新抛出当前正在处理的异常,并保留原始异常的堆栈跟踪。这是重新抛出异常的推荐方法,因为它保留了有关原始异常的有价值的调试信息。throw ex:当您使用 时throw ex,您会重新抛出异常对象ex——但会丢失原始异常的堆栈跟踪。相反,从调用点生成新的堆栈跟踪throw ex。这可能会使调试和跟踪异常的原始来源变得困难,这就是通常不鼓励这样做的原因。使用throw代替有助于throw ex维护异常上下文和堆栈跟踪,这对于调试、记录和分析应用程序中的异常至关重要。
处理块中出现的异常finally可能具有挑战性,因为您希望确保记录所有异常并防止掩盖原始异常。为了有效地处理这种情况,您可以使用以下方法:
finally。finally来捕获块内引发的任何异常。finally,将原始异常(如果有)存储到声明的变量中。finally,检查变量是否包含异常。如果是这样,请记录异常,再次抛出异常,或以其他适当的方式处理它。下面是这种方法的一个示例:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">originalException</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Code that can throw an exception</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Log or handle the caught exception</span>
<span style="color:var(--syntax-text-color)">originalException</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">finally</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Code that can throw an exception in the finally block</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Log or handle the exception thrown in the finally block</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">originalException</span> <span style="color:var(--syntax-text-color)">!=</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Log, rethrow or handle the originalException as needed</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
此方法可确保finally块中引发的任何异常都得到适当记录或处理,而不会掩盖块中发生的原始异常try。
C# 6.0 中引入的异常过滤器允许您向块添加条件逻辑,而catch无需额外的嵌套catch块。异常过滤器使您能够使用when关键字指定条件,该条件的计算结果必须true为要catch执行的块。
使用异常过滤器有以下好处:
catch。catch允许您根据过滤条件 使用单个块处理多种异常类型。以下是在 C# 中使用异常过滤器的示例:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Code that can throw an exception</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">InvalidOperationException</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-name-color)">when</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">Message</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">Contains</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"InvalidOperation"</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle InvalidOperationException with a specific message</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">InvalidOperationException</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle other InvalidOperationException instances</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-name-color)">when</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">Message</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">StartsWith</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Error"</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle other exceptions with a message starting with "Error"</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
在上面的示例中,catch 块根据关键字中指定的条件执行when。这使您可以使用干净且可读的代码来处理不同的异常和场景。
当您逐步学习 C# 面试问题中的异常处理综合指南时,请记住,了解基础知识并了解最新的语言功能将使您能够处理最具挑战性的面试场景。
现在,让我们继续讨论在 C# 中进行异步编程时经常出现的另一个关键主题。
在异步编程中,当使用不正确的方法处理异常并同步调用异步方法时,可能会出现潜在的死锁情况。以下是此类场景的示例:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">async</span> <span style="color:var(--syntax-text-color)">Task</span> <span style="color:var(--syntax-name-color)">ProcessDataAsync</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-text-color)">data</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-declaration-color)">await</span> <span style="color:var(--syntax-name-color)">GetRemoteDataAsync</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">await</span> <span style="color:var(--syntax-name-color)">SaveDataAsync</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">data</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle the exception here</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">async</span> <span style="color:var(--syntax-declaration-color)">void</span> <span style="color:var(--syntax-name-color)">Button_Click</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">object</span> <span style="color:var(--syntax-text-color)">sender</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">RoutedEventArgs</span> <span style="color:var(--syntax-text-color)">e</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// This line can lead to a deadlock</span>
<span style="color:var(--syntax-name-color)">ProcessDataAsync</span><span style="color:var(--syntax-text-color)">().</span><span style="color:var(--syntax-name-color)">Wait</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
在上面的示例中,ProcessDataAsync从事件处理程序调用该方法,其中该Wait()方法用于使异步调用同步。此方法可能会导致死锁,因为 UI 线程被阻塞等待ProcessDataAsync完成,而方法本身则等待 UI 线程上继续执行。
为了避免死锁,在异步编程中处理异常时应遵循以下最佳实践:
await关键字而不是Wait()or Result。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">async</span> <span style="color:var(--syntax-declaration-color)">void</span> <span style="color:var(--syntax-name-color)">Button_Click</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">object</span> <span style="color:var(--syntax-text-color)">sender</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">RoutedEventArgs</span> <span style="color:var(--syntax-text-color)">e</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">await</span> <span style="color:var(--syntax-name-color)">ProcessDataAsync</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
ConfigureAwait(false)不需要在原始上下文中恢复的任务,这有助于防止死锁。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">async</span> <span style="color:var(--syntax-text-color)">Task</span> <span style="color:var(--syntax-name-color)">ProcessDataAsync</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-text-color)">data</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-declaration-color)">await</span> <span style="color:var(--syntax-name-color)">GetRemoteDataAsync</span><span style="color:var(--syntax-text-color)">().</span><span style="color:var(--syntax-name-color)">ConfigureAwait</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">await</span> <span style="color:var(--syntax-name-color)">SaveDataAsync</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">data</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">ConfigureAwait</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle the exception here</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
通过遵循这些最佳实践,您可以在使用 C# 处理异常和异步编程时避免死锁情况。
AggregateException:这是一种特殊的异常类型,可以在其InnerExceptions属性中保存多个异常。AggregateException主要用在任务并行库 (TPL) 中,用于处理单个操作生成多个任务并且其中一个或多个任务引发异常的情况。通过使用AggregateException,TPL 可以收集各个任务引发的所有异常,并将它们呈现为单个对象以进行异常处理。TargetInvocationException:当通过反射调用的方法(例如,using MethodInfo.Invoke())抛出异常时,会抛出此异常。InnerException对象的属性保存目标TargetInvocationException方法引发的实际异常。在处理 时TargetInvocationException,必须检查并处理其InnerException属性,以获取原始异常的相关信息。AggregateException.InnerException:此属性是类的一个便利属性AggregateException,它返回集合中的第一个异常InnerExceptions,或者null集合是否为空。当处理包含AggregateException单个异常时,此属性非常有用。但是,当集合中有多个异常时InnerExceptions,要处理所有异常,您应该迭代集合并单独处理每个异常。总之,AggregateException用于处理并行操作中任务引发的多个异常,而TargetInvocationException用于通过反射调用方法时处理异常。在这两种情况下,分析InnerException或InnerExceptions属性以有效地理解和处理原始异常非常重要。
在 C# 中使用Task类和Parallel库时,您可能会遇到跨线程异常,因为这些类通常在不同线程中执行代码。可以通过以下最佳实践来实现跨线程异常的异常处理:
ContinueWith方法来处理与任务相关的异常。该TaskContinuationOptions.OnlyOnFaulted选项确保仅当先行任务引发异常时才运行延续。例如:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-text-color)">Task</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">Run</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-text-color)">=></span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Code that can throw an exception</span>
<span style="color:var(--syntax-text-color)">})</span>
<span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">ContinueWith</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">antecedentTask</span> <span style="color:var(--syntax-text-color)">=></span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle the exception from the antecedent task</span>
<span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-text-color)">exception</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-text-color)">antecedentTask</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">Exception</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">},</span> <span style="color:var(--syntax-text-color)">TaskContinuationOptions</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">OnlyOnFaulted</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>
Parallel库(例如,Parallel.ForEach等)Parallel.Invoke时,AggregateException当一个或多个任务遇到异常时会抛出 。您可以捕获AggregateException来处理跨线程异常,然后使用该InnerExceptions属性来访问各个异常。例如:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">Parallel</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">ForEach</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">data</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">item</span> <span style="color:var(--syntax-text-color)">=></span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Code that can throw an exception</span>
<span style="color:var(--syntax-text-color)">});</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">AggregateException</span> <span style="color:var(--syntax-text-color)">aggregateEx</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">foreach</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-text-color)">innerEx</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-text-color)">aggregateEx</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">Flatten</span><span style="color:var(--syntax-text-color)">().</span><span style="color:var(--syntax-text-color)">InnerExceptions</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle each individual exception</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
通过遵循这些最佳实践,您可以在使用C# 中的Task类和库时有效地实现跨线程异常的异常处理。Parallel在这两种情况下,分析Task或AggregateException对象内的异常以正确处理异常非常重要。
C# 中的类ExceptionDispatchInfo(在 .NET Framework 4.5 和 .NET Core 中引入)允许您捕获异常,包括其堆栈跟踪和原始上下文,并在稍后再次抛出它,同时保留原始信息。此功能在异步方法中特别有用,在异步方法中,使用经典throw语句重新抛出异常将生成新的异常并清除原始异常的堆栈跟踪。
使用该类ExceptionDispatchInfo:
ExceptionDispatchInfo.Capture()方法,传入要捕获的异常。该方法返回一个ExceptionDispatchInfo实例。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-text-color)">ExceptionDispatchInfo</span> <span style="color:var(--syntax-text-color)">capturedException</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-text-color)">ExceptionDispatchInfo</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">Capture</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">exception</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>
Throw()上的方法。ExceptionDispatchInfo
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-text-color)">capturedException</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">Throw</span><span style="color:var(--syntax-text-color)">();</span>
</code></span></span>
使用该类ExceptionDispatchInfo提供了一些主要好处,例如:
在 C# 中的异常处理上下文中,“第一次机会”和“第二次机会”异常是用于描述可以向应用程序的调试器通知异常的不同阶段的术语:
catch块来处理异常。在执行该catch块之前,调试器会收到第一次机会异常事件的通知。在大多数情况下,首次异常不会造成任何性能影响,因为它们代表应用程序预期捕获和处理的正常异常。理想情况下,您应该仅在开发和调试期间记录或处理第一次机会的异常,以帮助及早发现潜在问题。通常没有必要也不建议在生产代码中处理第一次机会异常,因为这可能会带来开销并对应用程序性能产生负面影响。catch块来处理异常,则调试器会再次收到第二次机会异常事件的通知。此时,异常被视为未处理,应用程序将默认终止。第二次机会异常可能会对应用程序性能和稳定性产生重大影响,因为它们表明未处理的异常可能导致应用程序崩溃。在 C# 中有效处理第一次和第二次机会异常:
try-catch块、记录异常以及对异常情况做出适当响应,以确保应用程序继续按预期运行。AppDomain.UnhandledException(对于控制台应用程序)或Application.DispatcherUnhandledException事件(对于 WPF 应用程序),可以帮助您记录未处理的异常,并可能在应用程序终止之前执行清理任务。请记住,通常不建议在生产代码中处理第二次机会异常以保持应用程序运行,因为这可能会导致进一步的问题和不稳定。处理这些异常应主要用于日志记录、诊断以及在应用程序退出之前尝试清理任务。
在我们的 C# 异常处理面试问题列表中,很明显,对于高效的 C# 开发人员来说,坚实的异常处理基础是必要的。到目前为止,您应该已经对异常处理的各个方面获得了宝贵的见解。
当我们进一步探索时,让我们讨论一个重点是在使用 C# 扩展方法时保持错误处理一致性的领域。
异常中立性意味着方法应该只抛出在其代码执行过程中发生的异常,而不应该引入新的异常或更改现有的异常,从而确保异常处理过程中行为的一致性。在 C# 扩展方法中保持异常中立性非常重要,原因如下:
为了确保扩展方法中的异常中立,请遵循以下准则:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">static</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-name-color)">ToUpperCase</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-text-color)">input</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Do not catch or alter exceptions within the extension method</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">input</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">ToUpper</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">static</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-name-color)">ToUpperCase</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-text-color)">input</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Do not add new exceptions unrelated to the extension method's functionality</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">input</span> <span style="color:var(--syntax-text-color)">==</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">throw</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">ArgumentNullException</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">nameof</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">input</span><span style="color:var(--syntax-text-color)">));</span> <span style="color:var(--syntax-comment-color)">// Don't do this</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">input</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">ToUpper</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">static</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-name-color)">CustomFunction</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-text-color)">input</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Perform some operation</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Do not modify or wrap the original exception</span>
<span style="color:var(--syntax-declaration-color)">throw</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// Preserve original exception, instead of: throw new CustomException("Message", ex);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
当应用程序已经在处理另一个异常时引发异常时,就会发生双错误异常。这些情况对于管理和调试来说可能具有挑战性,因为处理过程中引发的异常可能会掩盖或覆盖原始异常,从而难以识别初始问题的根本原因。
要在 C# 中有效处理双错误异常并维护有用的调试信息,可以按照以下步骤操作:
try-catch块处理外部catch块内的特定异常并保留原始异常。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Perform some operation that might throw an exception</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Attempt to handle the exception, e.g., log the exception or perform cleanup</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex2</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle the double-fault exception, e.g., log the exception or perform additional cleanup</span>
<span style="color:var(--syntax-comment-color)">// Preserve the original exception (ex) for debugging purposes</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
ExceptionDispatchInfo捕获原始异常和处理过程中引发的异常,保留它们的堆栈跟踪和上下文。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-text-color)">ExceptionDispatchInfo</span> <span style="color:var(--syntax-text-color)">originalException</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Perform some operation that might throw an exception</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">originalException</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-text-color)">ExceptionDispatchInfo</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">Capture</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-comment-color)">// Attempt to handle the exception, e.g., log the exception or perform cleanup</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">originalException</span> <span style="color:var(--syntax-text-color)">!=</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Perform additional handling or cleanup</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex2</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Preserve the original exception for debugging purposes</span>
<span style="color:var(--syntax-text-color)">originalException</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">Throw</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
即时 (JIT) 编译过程负责在 .NET 应用程序执行期间将公共中间语言 (CIL) 代码转换为可执行机器代码。JIT 编译期间可能会出现问题,例如内存损坏或元数据无效,这可能会导致异常。
当 JIT 编译过程中发生异常时,公共语言运行时 (CLR) 会进行如下处理:
InvalidProgramException. 此异常表示程序无法执行,因为它包含无效的 IL 代码或其元数据已损坏。TypeInitializationException. 此异常包装了类型初始化过程中发生的原始异常,并提供有关有问题类型的附加信息。在这两种情况下,当 JIT 编译期间发生异常时,应用程序通常会被终止,因为它表明应用程序的代码或元数据存在严重问题。要解决这些异常,必须通过分析应用程序代码来调查根本原因,确保正确的类型初始化并修复任何元数据损坏问题。
为了帮助诊断 JIT 编译异常,可以使用 Visual Studio、WinDbg 或 SOS (Son of Strike) 等调试工具来检查托管调用堆栈、IL 代码和元数据以获取相关信息。
Marshal.GetExceptionPointers和Marshal.GetExceptionCode是 C# 中类提供的方法System.Runtime.InteropServices.Marshal。这些方法可用于捕获 Windows 操作系统中结构化异常处理 (SEH) 期间发生的低级异常信息,例如访问冲突或被零除错误。
要使用这些方法,您需要使用C++/CLI 中可用的__try和__catch块或使用 P/Invoke 调用本机 Windows API 函数。但是,无法直接在 C# 中使用这些方法,因为 C# 不支持 SEH。
以下是使用 C++/CLI 在混合模式程序集中访问这些方法的示例:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#pragma managed(push, off)
</span>#<span style="color:var(--syntax-text-color)">include</span> <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-text-color)">windows</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">h</span><span style="color:var(--syntax-text-color)">></span>
<span style="color:var(--syntax-comment-color)">#pragma managed(pop)
</span><span style="color:var(--syntax-declaration-color)">using</span> <span style="color:var(--syntax-text-color)">namespace</span> <span style="color:var(--syntax-text-color)">System</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">using</span> <span style="color:var(--syntax-text-color)">namespace</span> <span style="color:var(--syntax-text-color)">System</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">Runtime</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">InteropServices</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">int</span> <span style="color:var(--syntax-name-color)">GetSEHExceptionCode</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">__try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">int</span> <span style="color:var(--syntax-text-color)">a</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-literal-color)">10</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">int</span> <span style="color:var(--syntax-text-color)">b</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">int</span> <span style="color:var(--syntax-text-color)">result</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-text-color)">a</span> <span style="color:var(--syntax-text-color)">/</span> <span style="color:var(--syntax-text-color)">b</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// Will cause a division by zero exception</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">__except</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">EXCEPTION_EXECUTE_HANDLER</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">int</span> <span style="color:var(--syntax-text-color)">exceptionCode</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-text-color)">Marshal</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">GetExceptionCode</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">Console</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">WriteLine</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Exception code: {0}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">exceptionCode</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">IntPtr</span> <span style="color:var(--syntax-text-color)">exceptionPointers</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-text-color)">Marshal</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">GetExceptionPointers</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">EXCEPTION_POINTERS</span><span style="color:var(--syntax-text-color)">*</span> <span style="color:var(--syntax-text-color)">pExceptionPointers</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-text-color)">static_cast</span><span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-text-color)">EXCEPTION_POINTERS</span><span style="color:var(--syntax-text-color)">*>(</span><span style="color:var(--syntax-text-color)">exceptionPointers</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">ToPointer</span><span style="color:var(--syntax-text-color)">());</span>
<span style="color:var(--syntax-text-color)">Console</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">WriteLine</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Exception address: {0}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">IntPtr</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">pExceptionPointers</span><span style="color:var(--syntax-text-color)">-></span><span style="color:var(--syntax-text-color)">ExceptionRecord</span><span style="color:var(--syntax-text-color)">-></span><span style="color:var(--syntax-text-color)">ExceptionAddress</span><span style="color:var(--syntax-text-color)">));</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
值得注意的是,使用低级 SEH 机制和混合模式程序集可能会导致潜在的问题和陷阱,例如使代码更难以阅读和维护、降低可移植性以及增加内存相关问题的风险。在大多数情况下,建议使用标准 C# 异常处理try-catch-finally块,因为它们提供了一种更直接、更受管理的异常处理方式。
损坏状态异常 (CSE) 是 CLR 遇到进程状态损坏时发生的异常类型,通常由外部事件或硬件故障触发。CSE 的示例包括内存不足、访问冲突或堆栈溢出。默认情况下,CLR 不允许捕获这些异常,因为它们可能表明潜在的危险情况或无法诊断的代码问题。
但是,在某些情况下,您可能需要处理 CSE,例如记录有关损坏的信息或尝试执行其他清理。在这些情况下,您可以将该HandleProcessCorruptedStateExceptionsAttribute属性与SecurityCriticalAttribute.
以下是如何使用这些属性来处理 CSE 的示例:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">using</span> <span style="color:var(--syntax-text-color)">System</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">using</span> <span style="color:var(--syntax-text-color)">System.Runtime.ExceptionServices</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">using</span> <span style="color:var(--syntax-text-color)">System.Security</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">CorruptedStateExceptionExample</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-text-color)">HandleProcessCorruptedStateExceptions</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">SecurityCritical</span><span style="color:var(--syntax-text-color)">]</span>
<span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">void</span> <span style="color:var(--syntax-name-color)">HandleCSE</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Perform some operation that might cause a corrupted state exception</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">Console</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">WriteLine</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Caught Corrupted State Exception: {0}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">Message</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-comment-color)">// Log the exception, perform cleanup, or take other handling actions</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
请记住,处理 CSE 只能在特定情况下谨慎进行。捕获和处理 CSE 可能会导致额外的错误或不稳定,因为进程状态已经损坏。
当我们深入研究 C# 异常处理面试问题时,必须记住,异常处理技术的深思熟虑的应用可以真正区分优雅地处理问题的优雅应用程序和难以调试和维护的脆弱应用程序。在下一节中,我们将讨论使用“using”语句时的一些潜在陷阱以及如何解决这些问题。
C# 中的语句using是管理资源(例如文件流或数据库连接)的便捷方式。它确保在离开块的范围时Dispose在实现接口的对象上调用该方法。虽然该语句简化了资源管理,但存在与异常处理相关的潜在陷阱:IDisposableusingusing
IDisposable,Dispose则不会调用该方法,因为该对象尚未完全实例化。这可能会导致资源泄漏。解决方法:在块外显式创建对象using,使用try-catch-finally块,如果对象已成功创建,则 Dispose在块中调用。finally
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-text-color)">IDisposableObject</span> <span style="color:var(--syntax-text-color)">obj</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">obj</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">IDisposableObject</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-comment-color)">// Perform operations with the object</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle exception</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">finally</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">obj</span><span style="color:var(--syntax-text-color)">?.</span><span style="color:var(--syntax-name-color)">Dispose</span><span style="color:var(--syntax-text-color)">();</span> <span style="color:var(--syntax-comment-color)">// Call Dispose if the object has been instantiated</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
Dispose,该异常将传播到块之外using,可能会掩盖任何先前的异常。解决方法:使用块实现对象Dispose的方法,在方法内妥善记录或处理异常,而不传播异常。 IDisposabletry-catch
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">IDisposableObject</span> <span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">IDisposable</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">public</span> <span style="color:var(--syntax-declaration-color)">void</span> <span style="color:var(--syntax-name-color)">Dispose</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Perform cleanup and resource deallocation</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Log the exception, taking appropriate actions without propagating the exception</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
通过了解这些潜在的陷阱并应用适当的解决方法,您可以确保应用程序中正确的异常处理,同时仍然利用该语句提供的便利和资源管理优势using。
在 C# 中设计自定义异常处理策略时,需要在使用专用异常类和使用通用Exception类之间进行平衡。以下是两种方法之间的主要权衡:
专门的异常类
优点:
缺点:
通用异常类(Exception)
优点:
Exception类可以简化异常处理代码,减少自定义异常类的数量。缺点:
Exception类会使确定错误的具体原因变得更加困难。最佳方法根据您的具体场景和要求而有所不同。一般来说,对于需要独特处理或需要额外上下文的不同错误场景,使用专门的异常类是一个很好的做法。如果异常不需要具体处理,可以使用通用Exception类来降低复杂性。
在 C# 应用程序中实现跨 AppDomain 通信的异常处理时,您需要考虑多个方面以确保正常运行和数据一致性。一些关键的考虑因素是:
[Serializable]属性,则无法在 AppDomain 之间传递,并且SerializationException会抛出异常。确保任何自定义异常类都标有该[Serializable]属性,并在需要时实现所需的序列化逻辑。AppDomainUnloadedException跨AppDomain通信期间可能会发生这种情况。确保您的异常处理策略考虑到此类异常并采取适当的操作。SerializationException则会抛出异常。确保包含自定义异常类的程序集已加载到两个 AppDomain 中。通过解决这些注意事项,您可以确保在 C# 应用程序中的跨 AppDomain 通信期间正确处理异常并保持正确的行为。
元组(System.Tuple和ValueTuple)可以在单个对象中存储多个值,但它们本质上不具有特殊的异常处理行为。在 C# 代码中访问元组或为其赋值时,可能会引发异常,就像任何其他对象或值类型一样。
处理元组中发生的异常遵循与其他 C# 代码相同的最佳实践:
try-catch-finally块:用块包围与元组一起使用的代码(例如,访问或分配值)try-catch-finally。捕获您期望的任何特定异常,并对任何意外异常使用通用 catch 块(例如catch (Exception ex))。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">int</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-declaration-color)">int</span> <span style="color:var(--syntax-text-color)">y</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">tuple</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">int</span> <span style="color:var(--syntax-text-color)">result</span> <span style="color:var(--syntax-text-color)">=</span> <span style="color:var(--syntax-text-color)">tuple</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">x</span> <span style="color:var(--syntax-text-color)">/</span> <span style="color:var(--syntax-text-color)">tuple</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">y</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">DivideByZeroException</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle divide-by-zero case.</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle any other exceptions.</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
try尽可能小并集中,以确保您捕获预期的异常,而不是无意中捕获不相关的异常。最后,如果您使用元组在方法之间传递值,请确保在处理可能在这些方法中引发异常的操作时进行正确的异常处理。
在 C# 中的结构化异常处理 (SEH) 上下文中,catch块和__except块用于处理由各种错误条件导致的异常。虽然这两个块都允许您处理异常,但它们之间存在关键区别:
捕捉块:
catch是一个 C# 关键字,是try-catch-finally语句的一部分,用于捕获try块内执行的托管代码引发的异常。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Code that may throw an exception.</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">FileNotFoundException</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle a specific FileNotFoundException.</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">catch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Exception</span> <span style="color:var(--syntax-text-color)">ex</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle all other exceptions.</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
__除了块:
__except是特定于 Windows 操作系统的关键字,是主要在本机 C/C++ 代码中使用的结构化异常处理 (SEH) 的一部分。__except不能直接在 C# 中使用,因此它可以在具有 C++/CLI 代码的混合模式程序集中使用,或者通过 P/Invoke 与本机 Windows API 一起使用。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">__try</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Code that may cause a low-level exception.</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">__except</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">EXCEPTION_EXECUTE_HANDLER</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Handle the exception.</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
作为一般规则,在 C# 中,您应该更喜欢使用语句catch中的块try-catch-finally来处理异常。该catch块是标准 C# 方法,并且与 .NET Framework 和 CLR 的其余部分一致地工作。__except仅在需要处理低级本机异常或正在使用混合模式程序集或对本机代码的 P/Invoke 调用的特定场景中考虑使用该块。
总之,C# 面试问题中异常处理的全面集合为您提供了在 C# 面试期间解决经常具有挑战性的异常处理主题的知识和信心。
无论您是刚刚开始接触 C# 的初学者还是经验丰富的开发人员,掌握异常处理概念和技术都将帮助您构建健壮、可靠且可维护的应用程序。祝您面试准备顺利!记住、练习和理解这些概念将为您作为 C# 开发人员带来成功。