异常处理是指程序在运行过程中,发生错误会导致程序退出,这种错误,就叫做异常。
因此处理这种错误,就称为异常处理。
引起异常的原因,一般是使用者不正当操作,开发者没有按规范的处理数据、使用技术不当导致的,极少情况是由于.NET内部错误引起的。
C# 异常处理时建立在四个关键词之上的:try、catch、finally 和 throw。
1、try:一个 try 块标识了一个将被激活的特定的异常的代码块。后跟一个或多个 catch 块。
2、catch:程序通过异常处理程序捕获异常。catch 关键字表示异常的捕获。
3、finally:finally 块用于执行给定的语句,不管异常是否被抛出都会执行。
4、throw:当问题出现时,程序抛出一个异常。使用 throw 关键字来完成。
C# 异常是使用类来表示的。
C# 中的异常类主要是直接或间接地派生于System.Exception.
(1).由System.SystemException派生的异常类型:
System.AccessViolationException 在试图读写受保护内存时引发的异常。
System.ArgumentException 在向方法提供的其中一个参数无效时引发的异常。
System.Collections.Generic.KeyNotFoundException
指定用于访问集合中元素的键与集合中的任何键都不匹配时所引发的异常。System.IndexOutOfRangeException 访问数组时,因元素索引超出数组边界而引发的异常。
System.InvalidCastException 因无效类型转换或显示转换引发的异常。
System.InvalidOperationException 当方法调用对于对象的当前状态无效时引发的异常。
System.InvalidProgramException
当程序包含无效Microsoft中间语言(MSIL)或元数据时引发的异常,这通常表示生成程序的编译器中有bug。System.IO.IOException 发生I/O错误时引发的异常。
System.NotImplementedException 在无法实现请求的方法或操作时引发的异常。
System.NullReferenceException 尝试对空对象引用进行操作时引发的异常。
System.OutOfMemoryException 没有足够的内存继续执行程序时引发的异常。
System.StackOverflowException 挂起的方法调用过多而导致执行堆栈溢出时引发的异常。
(2).由System.ArgumentException派生的异常类型:
System.ArgumentNullException 当将空引用传递给不接受它作为有效参数的方法时引发的异常。
System.ArgumentOutOfRangeException 当参数值超出调用的方法所定义的允许取值范围时引发的异常。
(3).由System.ArithmeticException派生的异常类型:
System.DivideByZeroException 试图用零除整数值或十进制数值时引发的异常。
System.NotFiniteNumberException 当浮点值为正无穷大、负无穷大或非数字(NaN)时引发的异常。
System.OverflowException 在选中的上下文中所进行的算数运算、类型转换或转换操作导致溢出时引发的异常。
(4).由System.IOException派生的异常类型:
System.IO.DirectoryNotFoundException 当找不到文件或目录的一部分时所引发的异常。
System.IO.DriveNotFoundException 当尝试访问的驱动器或共享不可用时引发的异常。
System.IO.EndOfStreamException 读操作试图超出流的末尾时引发的异常。
System.IO.FileLoadException 当找到托管程序却不能加载它时引发的异常。
System.IO.FileNotFoundException 试图访问磁盘上不存在的文件失败时引发的异常。
System.IO.PathTooLongException 当路径名或文件名超过系统定义的最大长度时引发的异常。
(5).其他常用异常类型:
ArrayTypeMismatchException 试图在数组中存储错误类型的对象。
BadImageFormatException 图形的格式错误。
DivideByZeroException 除零异常。
DllNotFoundException 找不到引用的dll。
FormatException 参数格式错误。
MethodAccessException 试图访问私有或者受保护的方法。
MissingMemberException 访问一个无效版本的dll。
NotSupportedException 调用的方法在类中没有实现。
PlatformNotSupportedException 平台不支持某个特定属性时抛出该错误。
try
{
//一些处理
}
catch (Exception e)
{
//一些处理
throw e; //CLR认为这里是异常的起始点
}
try
{
//一些处理
}
catch (Exception e)
{
//一些处理
throw; //CLR不会重新设置异常的起始点
}
设置捕获异常后,再次抛出异常。这种情况很少遇到,一般情况下不会这么处理,但是以上2种方式的处理方式差别很大。
即当我们抛出一个异常时, CLR会重新设置一个异常起始点。 CLR只记录最近一次异常抛出的位置。
throw e; 再次引发当前异常,导致CLR重新设置该异常的起始点。
throw; 引发当前位于计算堆栈上的异常对象,但不会导致CLR重新设置异常的起始点。
C#中使用throw和throw ex抛出异常,但二者是有区别的。
在C#中推荐使用throw;来抛出异常;throw
ex;会将到现在为止的所有信息清空,认为你catch到的异常已经被处理了,只不过处理过程中又抛出新的异常,从而找不到真正的错误源。throw
e重新抛出异常,并非转发原来的异常,而会更改包括StackTrace在内的许多异常内部信息;对于调用连很深情况,性能损耗超出想象。
string BuildStackTraceMessage(StackTrace stackTrace)
{
if (stackTrace != null)
{
var frameList = stackTrace.GetFrames();
var realFrameList = frameList.Where(i => i.GetMethod().DeclaringType != this.GetType() && i.GetFileLineNumber() > 0);
if (realFrameList.Any())
{
StringBuilder builder = new StringBuilder();
realFrameList = realFrameList.Reverse();
var lastFrame = realFrameList.Last();
builder.AppendFormat("源文件:{0}", lastFrame.GetFileName()).AppendLine();
builder.AppendFormat("行号:{0}", lastFrame.GetFileLineNumber()).AppendLine();
builder.AppendFormat("方法名:{0}", lastFrame.GetMethod().ToString()).AppendLine();
builder.AppendLine("堆栈跟踪:");
builder.AppendLine("=================================================================");
MethodBase method;
foreach (var frame in realFrameList)
{
method = frame.GetMethod();
builder.AppendFormat("> {0} 类下的第{1}行 {2} 方法", method.DeclaringType.ToString(), frame.GetFileLineNumber(), method.ToString()).AppendLine();
}
builder.AppendLine("=================================================================");
return builder.ToString();
}
}
return "没有堆栈信息";
}
C# 获取当前方法的名称空间、类名和方法名称
1.(new StackTrace()).GetFrame(1) // 0为本身的方法;1为调用方法
2.(new StackTrace()).GetFrame(1).GetMethod().Name; // 方法名
3.(new StackTrace()).GetFrame(1).GetMethod().ReflectedType.Name; // 类名
public string GetMethodInfo()
{
string str = "";
//取得当前方法命名空间
str += "命名空间名:" + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace + "\n";
//取得当前方法类全名 包括命名空间
str += "类名:" + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "\n";
//取得当前方法名
str += "方法名:" + System.Reflection.MethodBase.GetCurrentMethod().Name + "\n"; str += "\n";
//父方法
System.Diagnostics.StackTrace ss = new System.Diagnostics.StackTrace(true);
System.Reflection.MethodBase mb = ss.GetFrame(1).GetMethod();
//取得父方法命名空间
str += mb.DeclaringType.Namespace + "\n";
//取得父方法类名
str += mb.DeclaringType.Name + "\n";
//取得父方法类全名
str += mb.DeclaringType.FullName + "\n";
//取得父方法名
str += mb.Name + "\n"; return str;
}