【发布时间】:2011-02-06 12:06:59
【问题描述】:
有没有更好的方法来忽略 C# 中的异常,而不是将其放在 try catch 块中并且在 catch 中什么也不做?我发现这种语法很麻烦。对于代码块,我不能简单地“标记”它,以便运行时知道要忽略哪些异常吗?
【问题讨论】:
-
我知道忽略异常是一种不好的编程习惯,但我的问题不是这样。我看不出有一个空的 catch 块有什么意义,因此是这个问题。
有没有更好的方法来忽略 C# 中的异常,而不是将其放在 try catch 块中并且在 catch 中什么也不做?我发现这种语法很麻烦。对于代码块,我不能简单地“标记”它,以便运行时知道要忽略哪些异常吗?
【问题讨论】:
我不认为有什么技巧可以避免异常但是你可以使用下面的代码sn-p:
public void IgnoreExceptions(Action act)
{
try
{
act.Invoke();
}
catch { }
}
使用方法如下:
IgnoreExceptions(() => foo());
另一种解决方案是使用 AOP(面向方面的编程) - 有一个名为 PostSharp 的工具,它使您能够创建一个属性来捕获特定程序集/类/方法中的所有异常,这更接近您的实际情况正在寻找。
【讨论】:
Exception 类型的对象(此限制仅由 C# 强制执行)。所以,你应该重写你的catch 块:catch { };否则,某些不寻常的异常实际上可能会返回给调用者! -- 参见例如this blog article(大约往下两页)供参考。
你可以用 AOP 做到这一点。例如,Postsharp 将允许您轻松实现此类属性,该属性将跳过您应用此类属性的方法中的特定异常。如果没有 AOP,我看不到任何好的方法来做到这一点(如果我们假设有一种好的方法来做这些事情;))。
使用 Postsharp,您将能够以这种方式装饰您的方法:
[IgnoreExceptions(typeof(NullReferenceException), typeof(StackOverflowException))]
void MyMethod() { ... }
【讨论】:
我不知道有什么机制可以让你这样做。
通常,忽略异常也被认为是一种非常糟糕的做法。出于充分的理由(或应该始终)提出例外;如果不出意外,您至少应该记录它们。
如果您知道某种类型的异常对您的应用程序并不重要,您可以使用Application.UnhandledException 事件来防止它崩溃,检查这种异常。请注意,这仍会将异常通过所有堆栈帧传播到最底部。
【讨论】:
我想贡献我根据之前的答案创建的扩展方法。希望它可以帮助某人。
/// <summary>
/// Extension methods for <see cref="Action"/> objects.
/// </summary>
public static class ActionExtensions
{
/// <summary>
/// Executes the <paramref name="action"/> and ignores any exceptions.
/// </summary>
/// <remarks>
/// This should be used in very rare cases.
/// </remarks>
/// <param name="action">The action to execute.</param>
public static void IgnoreExceptions(this Action action)
{
try { action(); }
catch { }
}
/// <summary>
/// Extends an existing <see cref="Action"/> so that it will ignore exceptions when executed.
/// </summary>
/// <param name="action">The action to extend.</param>
/// <returns>A new Action that will ignore exceptions when executed.</returns>
public static Action AddIgnoreExceptions(this Action action)
{
return () => action.IgnoreExceptions();
}
}
还有单元测试:
[TestClass]
public class ActionExtensionsTests
{
[TestMethod]
public void IgnoreException()
{
Action justThrow = () => { throw new InvalidOperationException(); };
justThrow.IgnoreExceptions();
}
[TestMethod]
public void AddIgnoreException()
{
Action justThrow = () => { throw new InvalidOperationException(); };
var newAction = justThrow.AddIgnoreExceptions();
newAction();
}
}
【讨论】:
public static void Ignore<T>(Action a) where T : Exception
{
try
{
a();
}
catch (T)
{
}
}
使用方法:
Ignore<InvalidOperationException>(() => foo());
【讨论】:
没有。当出现异常时,它们会返回调用堆栈,直到它们被 catch 块处理或整个进程终止。
【讨论】:
没有。如果抛出异常,通常是已经发生的严重错误。你不想忽略它。
相反,您应该重写代码以检查错误,并且只有当它确实失败时,才会抛出异常。
例如,使用 Int32.TryParse 而不是 Int32.Parse 来检查对象是否为有效整数。请记住,异常在强制转换时非常昂贵,而且许多强制转换会严重影响应用程序的性能。
【讨论】:
空的 catch 块是一种非常臭的代码气味。简而言之,您不应该追求一种速记方式来编写它们。
第 1 条规则是,“如果你不能处理,就不要抓住它。” 规则 #1a 是,“如果您实际上没有处理异常,请重新抛出它。”
如果您只是想防止应用崩溃,则可以在大多数情况下使用更合适的机制。 .NET 包括 Application、Dispatcher 和 AppDomain 级别的 UnhandledException 事件,以及专门用于通知您后台线程上未处理的异常的事件。在此级别,如果您无法验证应用的状态,最好的选择可能是通知用户发生了一些不好的事情并终止应用。
【讨论】: