在C#中,我如何定义自己的异常?

在C#中,我如何定义自己的异常?,c#,exception,C#,Exception,在C#中,如何定义自己的异常? 看来我已经开始了一场有点例外的分包战斗。根据您遵循的Microsoft最佳实践指南,您可以从System.Exception或System.ApplicationException继承。有一篇很好(但很旧)的博客文章试图澄清这一困惑。现在我将保留我的示例,但您可以阅读本文并根据需要进行选择: 不再有战斗了!感谢Frederik指出FxCop规则CA1058,该规则规定您的异常应继承自System.Exception而非System.ApplicationExce

在C#中,如何定义自己的异常?


看来我已经开始了一场有点例外的分包战斗。根据您遵循的Microsoft最佳实践指南,您可以从System.Exception或System.ApplicationException继承。有一篇很好(但很旧)的博客文章试图澄清这一困惑。现在我将保留我的示例,但您可以阅读本文并根据需要进行选择:

不再有战斗了!感谢Frederik指出FxCop规则CA1058,该规则规定您的异常应继承自System.Exception而非System.ApplicationException:


定义一个从Exception继承的新类(我已经包含了一些构造函数…但您不必拥有它们):

以及代码中要抛出的其他内容:

throw new MyException("My message here!");

编辑

已使用更改进行更新,以确保可序列化异常。详情可在此找到:

请密切关注有关向异常类添加自定义属性时需要采取的步骤的部分。

谢谢伊戈尔打电话给我

要定义:

public class SomeException : Exception
{
    // Add your own constructors and properties here.
}
投掷:

throw new SomeException();
定义:

public class CustomException : Exception
{
   public CustomException(string Message) : base (Message)
   {
   }
}
投掷:

throw new CustomException("Custom exception message");

创建自己的异常的指导原则(紧挨着类应该从异常继承的事实)

  • 通过添加
    [serializable]
    属性,确保类是可序列化的
  • 提供异常使用的公共构造函数:

    MyException ();
    
    MyException (string message);
    
    MyException (string message, Exception innerException);
    
因此,理想情况下,您的自定义
异常
至少应如下所示:

[Serializable]
public class MyException : Exception
{
    public MyException ()
    {}

    public MyException (string message) 
        : base(message)
    {}

    public MyException (string message, Exception innerException)
        : base (message, innerException)
    {}    
}
关于是否应从
异常
应用程序异常
继承的事实: FxCop有一条规则,规定您应避免继承自
ApplicationException

CA1058:Microsoft.Design:
改变 “MyException”的基类型,以便 它不再延伸 “ApplicationException”。这个基地 异常类型不提供任何 框架的附加值 上课。扩展“System.Exception”或 现有的未密封异常类型 相反不要创建新的异常 基类型,除非有特定的 在创建 整个类的捕获处理程序 例外情况


请参阅有关此规则的信息。

您可以定义自己的异常

用户定义的异常类派生自该类

您可以看到以下代码:

using System;
namespace UserDefinedException
{
   class TestTemperature
   {
      static void Main(string[] args)
      {
         Temperature temp = new Temperature();
         try
         {
            temp.showTemp();
         }
         catch(TempIsZeroException e)
         {
            Console.WriteLine("TempIsZeroException: {0}", e.Message);
         }
         Console.ReadKey();
      }
   }
}
public class TempIsZeroException: ApplicationException
{
   public TempIsZeroException(string message): base(message)
   {
   }
}
public class Temperature
{
   int temperature = 0;
   public void showTemp()
   {
      if(temperature == 0)
      {
         throw (new TempIsZeroException("Zero Temperature found"));
      }
      else
      {
         Console.WriteLine("Temperature: {0}", temperature);
      }
   }
}
以及抛出一个异常

如果对象直接或间接派生自类,则可以抛出该对象

来自微软的:

要定义自己的异常类,请执行以下操作:

  • 定义从异常继承的类。如有必要,请定义类所需的任何唯一成员,以提供有关异常的其他信息。例如,ArgumentException类包括一个ParamName属性,该属性指定参数的名称,该参数的参数导致了异常,RegexMatchTimeoutException属性包括一个MatchTimeout属性,该属性指示超时间隔

  • 如有必要,请覆盖要更改或修改其功能的任何继承成员。请注意,大多数现有的Exception派生类不会重写继承成员的行为

  • 确定自定义异常对象是否可序列化。序列化使您能够保存有关异常的信息,并允许服务器和客户端代理在远程处理上下文中共享异常信息。要使异常对象可序列化,请使用SerializableAttribute属性对其进行标记

  • 定义异常类的构造函数。通常,异常类具有以下一个或多个构造函数:

    • Exception(),它使用默认值初始化新异常对象的属性

    • 异常(字符串),它使用指定的错误消息初始化新的异常对象

    • 异常(字符串,异常),它使用指定的错误消息和内部异常初始化新的异常对象

    • 异常(SerializationInfo,StreamingContext),它是一个受保护的构造函数,用于从序列化数据初始化新的异常对象。如果选择使异常对象可序列化,则应实现此构造函数

    示例:

    using System;
    using System.Runtime.Serialization;
    
    [Serializable()]
    public class NotPrimeException : Exception
    {
       private int _notAPrime;
       public int NotAPrime { get { return _notAPrime; } }
    
       protected NotPrimeException() : base()
       { }
    
       public NotPrimeException(int value) : base(String.Format("{0} is not a prime number.", value))
       {
          _notAPrime = value;
       }
    
       public NotPrimeException(int value, string message) : base(message)
       {
          _notAPrime = value;
       }
    
       public NotPrimeException(int value, string message, Exception innerException) : base(message, innerException)
       {
          _notAPrime = value;
       }
    
       protected NotPrimeException(SerializationInfo info, StreamingContext context) : base(info, context)
       { }
    }
    
    throw new NotPrimeException(prime, "This is not a prime number."));
    
    try
    {
       ...
    }
    catch (NotPrimeException e)
    {
       Console.WriteLine( "{0} is not prime", e.NotAPrime );
    }
    
    投掷中的用法:

    using System;
    using System.Runtime.Serialization;
    
    [Serializable()]
    public class NotPrimeException : Exception
    {
       private int _notAPrime;
       public int NotAPrime { get { return _notAPrime; } }
    
       protected NotPrimeException() : base()
       { }
    
       public NotPrimeException(int value) : base(String.Format("{0} is not a prime number.", value))
       {
          _notAPrime = value;
       }
    
       public NotPrimeException(int value, string message) : base(message)
       {
          _notAPrime = value;
       }
    
       public NotPrimeException(int value, string message, Exception innerException) : base(message, innerException)
       {
          _notAPrime = value;
       }
    
       protected NotPrimeException(SerializationInfo info, StreamingContext context) : base(info, context)
       { }
    }
    
    throw new NotPrimeException(prime, "This is not a prime number."));
    
    try
    {
       ...
    }
    catch (NotPrimeException e)
    {
       Console.WriteLine( "{0} is not prime", e.NotAPrime );
    }
    
    在try/catch中的用法:

    using System;
    using System.Runtime.Serialization;
    
    [Serializable()]
    public class NotPrimeException : Exception
    {
       private int _notAPrime;
       public int NotAPrime { get { return _notAPrime; } }
    
       protected NotPrimeException() : base()
       { }
    
       public NotPrimeException(int value) : base(String.Format("{0} is not a prime number.", value))
       {
          _notAPrime = value;
       }
    
       public NotPrimeException(int value, string message) : base(message)
       {
          _notAPrime = value;
       }
    
       public NotPrimeException(int value, string message, Exception innerException) : base(message, innerException)
       {
          _notAPrime = value;
       }
    
       protected NotPrimeException(SerializationInfo info, StreamingContext context) : base(info, context)
       { }
    }
    
    throw new NotPrimeException(prime, "This is not a prime number."));
    
    try
    {
       ...
    }
    catch (NotPrimeException e)
    {
       Console.WriteLine( "{0} is not prime", e.NotAPrime );
    }
    

    要创建自己的异常,可以使用以下示例:

    [Serializable()]
    public class InvalidExampleException : System.Exception
    {
       public InvalidExampleException() : base() { }
       public InvalidExampleException(string message) : base(message) { }
       public InvalidExampleException(string message, System.Exception inner) : base(message, inner) { }
    
       protected InvalidExampleException(System.Runtime.Serialization.SerializationInfo info,
        System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
    }
    
    如中所述,c#中的异常至少需要这四个构造函数

    然后,要在代码中使用此异常,您只需执行以下操作:

    using InvalidExampleException;
    public class test
    {
        public int i = 0;
    
        public void check_i()
        {
            if (i == 0) // if i = 0: error
            {
                // exception
                throw new InvalidExampleException("Index is zero");
            }
        }
    }
    

    您可以使用“exception”类作为基类来创建自定义异常

    public class TestCustomException: Exception
    {  
    
      public TestCustomException(string message, Exception inner)
        : base(message, inner)
      {
    
      } 
    }
    
    完整的控制台示例

    class TestCustomException : Exception
    {
    
        public TestCustomException(string message) : base(message)
        {
            this.HelpLink = "Sample Link details related to error";
            this.Source = "This is source of Error";
        }
    
    }
    
    class MyClass
    {
        public static void Show()
        {
            throw new TestCustomException("This is Custom Exception example in C#");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                MyClass.Show();
            }
            catch (TestCustomException ex)
            {
                Console.WriteLine("Error Message:-" + ex.Message);
                Console.WriteLine("Hyper Link :-" + ex.HelpLink);
                Console.WriteLine("Source :- " + ex.Source);
                Console.ReadKey();
            }
        }
    }
    

    资料来源:

    感谢您(但不是+1)以尽可能少的字数提出了一个易懂的问题。我同意下面的所有答案,但希望指出您应该始终直接从System.ApplicationException继承。MS对此的指导方针是立即区分系统异常和用户定义的异常。无论您选择哪一个,都要编写基类并保持异常用法的一致性。@Joel-说话要小心。Microsoft最佳实践文档在自定义例外方面自相矛盾。我改变了答案,因为OP的使用似乎更倾向于应用程序异常。查看这篇关于矛盾的帖子:@Justin Niessner:如果你想在AppDomain中抛出自定义异常,就必须使其可序列化。不建议从ApplicationException继承。它毫无理由地增加了继承层次结构。请参见和@Gabe Moothart:“您可以避免与自定义属性和序列化相关的麻烦”--仅当您的自定义属性