今天在阅读 .net 源码时发现微软对所有使用枚举类型的地方对枚举值进行了检测,在检测不通过时抛出了异常。
if (!System.Windows.Forms.ClientUtils.IsEnumValid(value, (int) value, 0, 4)) { throw new InvalidEnumArgumentException("value", (int) value, typeof(PictureBoxSizeMode)); }
下面的demo展示了枚举类型的正确使用方法,异常的原因和抛出枚举异常的方法:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { class Program { enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat }; static void Main(string[] args) { try { ConsoleDay(Days.Fri); //正确的使用枚举 ConsoleDay((Days)2); ConsoleDay((Days)8); //枚举异常的来源 } catch (Exception err) { Console.WriteLine(err.Message); } Console.ReadLine(); } static void ConsoleDay(Days day) { int dayInt = (int)day; if (dayInt < 0 || dayInt > 6)//检测枚举 { throw new InvalidEnumArgumentException("day", dayInt, typeof(Days));//抛出枚举异常 } Console.WriteLine(day); } } }
关于异常,除了在各个接口中使用 try catch finally 来处理外,还可以对整个程序的异常统一处理。
以 winform 为例,可以修改 program.cs 文件:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; namespace PrintTest { static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); //处理 UI 线程的异常 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); //处理非 UI 线程的异常 Application.Run(new Form1()); } static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { MessageBox.Show(e.Exception.Message); } private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { Console.WriteLine(e.ExceptionObject.ToString()); MessageBox.Show(e.ExceptionObject.ToString()); } } }
我们可以依赖 .net 来生成异常,也可以自己 new 一个异常,这样可以定制异常的 message:
class Program {static void Main(string[] args) { try { ConsoleDivision(4, 2); ConsoleDivision(4, 0); } catch (Exception err) { Console.WriteLine(err.Message); } Console.ReadLine(); } static void ConsoleDivision(int num1, int num2) { //if (num2 == 0) //{ // throw new DivideByZeroException("num2不能是零"); //} Console.WriteLine(num1 / num2); } }
当程序的结构较深时需要嵌套异常,使用 new Exception() 的重载,方便定位:
class Program { static void Main(string[] args) { try { DoSomeThing(); } catch (Exception err) { string innerMsg = err.InnerException == null ? "" : " innerExceptionMessage:" + err.InnerException.Message; Console.WriteLine(err.Message + innerMsg); } Console.ReadLine(); } static void DoSomeThing() { try { ConsoleDivision(4, 0); } catch (Exception err) { throw new Exception("DoSomeThing异常", err); } } static void ConsoleDivision(int num1, int num2) { if (num2 == 0) { throw new DivideByZeroException("num2不能是零啊"); } Console.WriteLine(num1 / num2); } }
当需要区分异常时可以使用多个 catch (注意将catch(Exception err)放在最后面,因为 Exception 是所有异常的基类,必然捕获),可以自定义各种类型的异常。
namespace ConsoleApplication1 { class MyException : Exception { public MyException() : base() { } public MyException(string str) : base(str) { } public MyException(string str, Exception inner) : base(str, inner) { } } class Program { static void Main(string[] args) { try { throw new MyException(""); //throw new DivideByZeroException(); } catch (MyException err) { Console.WriteLine("MyException捕获" + err.Message); } catch (Exception err) { Console.WriteLine("Exception捕获" + err.Message); } Console.ReadLine(); } } }