在C#中引发异常的最佳方式是什么?

57

传统上,我部署了一组网页,允许手动验证核心应用程序功能。其中一个例子是LoggerTest.aspx,它生成并记录一个测试异常。我一直选择使用类似以下代码片段的方法引发DivideByZeroException:

<%@ Page Language="C#" %>
        
<%@ Import Namespace="System" %>
        
<script runat="server">
    void Page_Load(object sender, EventArgs e)
    {
        try
        {
            int x = 0;
            int y = 1 / x;
        }
        catch (DivideByZeroException ex)
        {
            // Log the exception.
        }
    }
</script>
try
{
   int zero = 0;
   int result = 100 / zero;
}
catch (DivideByZeroException ex)
{
   LogHelper.Error("TEST EXCEPTION", ex);
}

代码可以正常工作,但我觉得必须有更优雅的解决方案。在C#中引发异常是否有最佳方法?


感谢您的反馈。我已将GalacticCowboy的答案标记为正确答案,因为根据问题的措辞,它显然是正确的答案。再次感谢您的反馈,如果问题不够清晰,很抱歉。 - Ben Griswold
对于那些认为“这个问题肯定还有更多”的人,你是对的。本质上,我正在寻找一种最佳方法来引发/导致/模拟异常。正如James Curran所说,我追求的是异常的发生而不是异常的抛出。强制引发DivideByZeroException是我的默认策略,但我认为可能还有其他方法或者甚至是更好的异常可以引发。很可能抛出和“引发”异常之间没有区别。至少大多数答案似乎都持有这种观点。 - Ben Griswold
12个回答

79
try
{
  throw new DivideByZeroException();
}
catch (DivideByZeroException ex)
{
  LogHelper.Error("TEST EXCEPTION", ex);
}

2
这有点危险。当用户显式引发CLR通常引发的异常时,CLR的行为会有所不同。有关更多详细信息,请参见此帖子:http://blogs.msdn.com/jaredpar/archive/2008/10/22/when-can-you-catch-a-stackoverflowexception.aspx - JaredPar
然而,除零异常本质上是可测试和可抛出的,而无需实际尝试执行除法。堆栈溢出是一种不同的情况,并且有相应的文档记录。其他异常也会注明“不打算由客户端代码抛出”类型的注释。 - GalacticCowboy
这仅适用于StackOverfloWExceptions。那是因为很多时候,catch子句仍然会深入堆栈并导致堆栈溢出。当CLR抛出该异常时,它永远无法被捕获或处理。 - configurator
换句话说,仅仅因为CLR会引发某个异常并不意味着我就不应该引发它。 - GalacticCowboy
1
@JaredPar 您的评论让我相信,在编程中没有什么是确定的,我感觉自己就像活在递归的无知中。当我学习一些东西时,我认为我知道了它,但不!那么快,总会有一些规则的例外。我已经厌倦了等待一个确定自己确实知道某些事情的时刻 :( - dragan.stepanovic
@kobac 我有同样的感觉。每次我讨论线程时,我都会 a) 学到一些东西,b) 意识到以前写的代码实际上是错误的。有时这让人感到沮丧。编程中缺乏确定性是软件脆弱的原因之一。 - JaredPar

44

简短回答:

throw new Exception("Test Exception");

您需要

using System;

你不应该直接使用 Exception,而是应该使用现有的实现或创建自己的实现。Exception 太过于通用。.NET 框架设计团队的 Brad Abrams 表示,他希望他们能够重新设计这个类,并使用私有构造函数来避免像这样的使用。 - Aaron Powell
这对于测试新的审计日志非常有用。非常基础,可能会出现错误。对我很有效,谢谢。 - JoshYates1980
已登录以投票支持此方法。我还没有看到不这样做的好理由,特别是对于测试记录器来说。 - VSO

5
        try
        {
            string a="asd";
            int s = Convert.ToInt32(a);
        }
        catch (Exception ex)
        {

            Response.Write(ex.Message);
        }

当出现异常 "Input string was not in a correct format." 时,表示输入的字符串格式不正确。


int s = int.Parse("asd"); - Deniz

5

为了测试目的,构建一个自定义异常?然后你可以添加任何想要异常携带的自定义属性,这些属性将在异常处理/日志记录过程中传递...

 [Serializable]
 public class TestException: ApplicationException
 {
     public TestException(string Message, 
                  Exception innerException): base(Message,innerException) {}
     public TestException(string Message) : base(Message) {}
     public TestException() {}

     #region Serializeable Code
     public TestException(SerializationInfo info, 
           StreamingContext context): base(info, context) { }
     #endregion Serializeable Code
 }

在你的类中
 try
 {  
      throw new TestException();
 }
 catch( TestException eX)
 {  
    LogHelper.Error("TEST EXCEPTION", eX);
 }

3
所以,让我为继续以你之前的方式进行辩护。您不想测试当抛出“DivideByZeroException”时会发生什么; 您要测试的是实际发生除以零的情况下会发生什么。
如果您没有看到区别,请考虑:您是否真的确定何时要检查“NullRefernceException”和何时要检查“ArgumentNullException”?

3

抛出异常在这里;

是吗?

我找到的例子是

        if (args.Length == 0)
        {
            throw new ArgumentException("A start-up parameter is required.");
        }

2
感谢反馈。我已将GalacticCowboy的答案标记为正确答案,因为从问题的措辞来看,它显然是正确的答案。
对于那些认为“这个问题肯定还有更多内容”的人,你们是正确的。实质上,我在寻找一种最佳方式来引发/导致/模拟异常。正如James Curran所说,我需要的是异常的发生而不是异常的抛出。强制引发DivideByZeroException是我的默认策略,但我想可能还有其他方法或者甚至是更好的异常类型可以使用。
很可能抛出异常和“引发”异常之间没有区别。至少大多数答案似乎都持有这种观点。
再次感谢反馈,如果问题不清楚,还请见谅。

1

throw new DivideByZeroException("一些信息");

还是我漏了什么?


1
如果您只是在测试LogHelper的Error方法,为什么要抛出异常呢?您只需要一个一行代码:
LogHelper.Error("TEST EXCEPTION", new Exception("This is a test exception"));

+1 给你,尽管这个问题比那个要更一般 - 什么是引发异常的首选方法? - GalacticCowboy

1
public class CustomException: Exception
{
     public CustomException(string message)
        : base(message) { }

}

// 如果(something == anything) { 抛出新的CustomException("自定义文本信息"); }

你可以尝试这个


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接