c# 闲谈异常处理

时间:2021-06-13 23:26:27

今天在阅读 .net 源码时发现微软对所有使用枚举类型的地方对枚举值进行了检测,在检测不通过时抛出了异常。

    if (!System.Windows.Forms.ClientUtils.IsEnumValid(value, (int) value, , ))
{
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));
ConsoleDay((Days)); //枚举异常的来源
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
Console.ReadLine();
}
static void ConsoleDay(Days day)
{
int dayInt = (int)day;
if (dayInt < || dayInt > )//检测枚举
{
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(, );
ConsoleDivision(, );
}
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(, );
}
catch (Exception err)
{
throw new Exception("DoSomeThing异常", err);
}
} static void ConsoleDivision(int num1, int num2)
{
if (num2 == )
{
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();
}
}
}