C#中异常处理一般不影响性能,所以应该返回必要的错误码或者打印Log以外,需要的地方必须加入异常处理。
一、.net异常处理和预定义异常类
.net内建异常类有:
System.SystemException .net CRL抛出的严重异常,例如抛出StackOverflowException,ArgumentException
System.ApplicationException 应用程序的异常,自定义了应用程序异常应该继承该类。
EndOfStreamException 这个异常通常是因为读到文件末尾而抛出的。
OverflowException 如果再checked环境下转换类型溢出就会抛出这个异常。
FormatException 格式转换异常,例如a转换为数字。
Exception 异常的基类,可以获取到所有没有预料到的异常;可以用它的Message属性获取异常详细信息。
异常处理执行逻辑:
// 用try避免没有导致程序崩溃
try
{
if(xxx)
throw new xxx; //
不抛出,而是由基类库中抛出是非常常见的。后面代码不再执行,跳转到catch块
}
// 出现了异常在这里处理
catch(CExceptionClass e)
{
}
// 无论如何都执行
finally
{
}
.net会将异常部分代码用一个更大的try块和catch块来处理,如果程序中没有catch处理异常,那么程序将会抛出异常而终止,并且系统提示异常信息。
所以如果是应用程序应该处理尽可能出现的异常,如果是库那么最好不要抛出自定义异常但但抛出.net预定义异常类。
实例:
using System;
namespace Wrox.ProCSharp.AdvancedCSharp
{
public class MainEntryPoint
{
public static void Main()
{
while ( true )
{
try
{
Console.Write("Input a number between 0 and 5 " +
"(or just hit return to exit)> ");
string userInput = Console.ReadLine();
if (userInput == "")
break;
int index = Convert.ToInt32(userInput);
if (index < 0 || index > 5)
throw new IndexOutOfRangeException(
"You typed in " + userInput);
Console.WriteLine("Your number was " + index);
}
catch (IndexOutOfRangeException e)
{
Console.WriteLine("Exception: " +
"Number should be between 0 and 5. " + e.Message);
}
catch (Exception e)
{
Console.WriteLine(
"An exception was thrown. Message was: " + e.Message);
}
catch
{
Console.WriteLine("Some other exception has occurred");
}
finally
{
Console.WriteLine("Thank you");
}
}
}
}
}
二、自定义异常类型
自定义异常类继承
ApplicationException类,提供构造函数和输出信息。
在使用try{}catch(){}finally块中嵌套的抛出和处理异常即可。
using System;
using System.IO;
namespace Wrox.ProCSharp.AdvancedCSharp
{
class MainEntryPoint
{
static void Main()
{
Console.Write("Please type in the name of the file " +
"containing the names of the people to be cold-called > ");
string fileName = Console.ReadLine();
ColdCallFileReader peopleToRing = new ColdCallFileReader();
try
{
peopleToRing.Open(fileName);
for (int i=0 ; i<peopleToRing.NPeopleToRing; i++)
{
peopleToRing.ProcessNextPerson();
}
Console.WriteLine("All callees processed correctly");
}
catch(FileNotFoundException)
{
Console.WriteLine("The file {0} does not exist", fileName);
}
catch(ColdCallFileFormatException e)
{
Console.WriteLine(
"The file {0} appears to have been corrupted", fileName);
Console.WriteLine("Details of problem are: {0}", e.Message);
if (e.InnerException != null)
Console.WriteLine(
"Inner exception was: {0}", e.InnerException.Message);
}
catch(Exception e)
{
Console.WriteLine("Exception occurred:\n" + e.Message);
}
finally
{
peopleToRing.Dispose();
}
Console.ReadLine();
}
}
class ColdCallFileReader :IDisposable
{
FileStream fs;
StreamReader sr;
uint nPeopleToRing;
bool isDisposed = false;
bool isOpen = false;
public void Open(string fileName)
{
if (isDisposed)
throw new ObjectDisposedException("peopleToRing");
fs = new FileStream(fileName, FileMode.Open);
sr = new StreamReader(fs);
try
{
string firstLine = sr.ReadLine();
nPeopleToRing = uint.Parse(firstLine);
isOpen = true;
}
catch (FormatException e)
{
throw new ColdCallFileFormatException(
"First line isn\'t an integer", e);
}
}
public uint NPeopleToRing
{
get
{
if (isDisposed)
throw new ObjectDisposedException("peopleToRing");
if (!isOpen)
throw new UnexpectedException(
"Attempt to access cold call file that is not open");
return nPeopleToRing;
}
}
public void Dispose()
{
if (isDisposed)
return;
isDisposed = true;
isOpen = false;
if (fs != null)
{
fs.Close();
fs = null;
}
}
public void ProcessNextPerson()
{
if (isDisposed)
throw new ObjectDisposedException("peopleToRing");
if (!isOpen)
throw new UnexpectedException(
"Attempt to access cold call file that is not open");
try
{
string name;
name = sr.ReadLine();
if (name == null)
throw new ColdCallFileFormatException("Not enough names");
if (name[0] == 'B')
{
throw new SalesSpyFoundException(name);
}
Console.WriteLine(name);
}
catch(SalesSpyFoundException e)
{
Console.WriteLine(e.Message);
}
finally
{
}
}
}
class SalesSpyFoundException : ApplicationException
{
public SalesSpyFoundException(string spyName)
: base("LandLine spy found, with name " + spyName)
{
}
public SalesSpyFoundException(string spyName, Exception innerException)
: base("LandLine spy found, with name " + spyName, innerException)
{
}
}
class ColdCallFileFormatException : ApplicationException
{
public ColdCallFileFormatException(string message)
: base(message)
{
}
public ColdCallFileFormatException(string message, Exception innerException)
: base(message, innerException)
{
}
}
class UnexpectedException : ApplicationException
{
public UnexpectedException(string message)
: base(message)
{
}
public UnexpectedException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}