1 不要捕捉到异常而什么都不干,如:
private void TestMethod(){
try{
//处理可能发生异常的业务逻辑
}
catch(Exception){
//这里啥也没干
}
}
上述代码捕捉到异常既没有做进一步的处理,也没有往上一级抛,而是把异常信息给吞了,这种做法是不对的,特别是如果发生异常的方法在类库中,更不能把异常信息给吞了,应该把异常信息往上抛给调用者处理,为什么要把异常信息抛给调用者呢?
举一个容易理解的例子:
我们都知道,每一种药的说明书上一般都写有禁忌的字眼用来告诉医生(或者使用者)哪些人不能使用这种药,如果说明书上没说明禁忌那些人不能使用,到时候出现问题(比如死人之类的),那么责任则由生产这种药的厂商负责。但是如果说明书上写有了相关的禁忌(相当于把异常抛给使用者),还出现问题,那就是医生(或者使用者)的责任了。
再说的通俗一点,我把不可避免的问题(异常)告诉你了,怎样做相应的处理处决于你。
再举一个例子:
假设你写了一个类库,但类库里面有一个方法在极端的情况下会发送异常,而你并没有把异常信息抛给使用你的类库的程序员,而是悄悄捕捉了而啥了没做。使用你的类库的程序员在调试的时候,测试某些极端的情况的时候,程序得不到想要的结果,而程序也没挂掉,那么使用你的类库的程序员在把自己写的程序都分析后还找不到问题所在,这时可能会傻眼了。这个例子说明的情况是:给调用者调试增加了难度。
上面两个例子可能举得不太恰当,知道大概意思就行了。
所以你的做法可以如下:
private void TestMethod(){
try{
//处理可能发生异常的业务逻辑
}
catch{
//往上抛
throw;
}
}
2 把错误信息以字符串的形式直接返回给调用者
如:
public string Calculate(int row,int column){
string result;
try{
result=计算返回结果的业务逻辑(可能发生异常);
}
catch(DivideByZeroException){
result="除数不能为0";
}
catch(OverflowException){
result="值太大了,溢出了";
}
return result;
}
3 把异常往上抛后,同时有些操作还需要回滚
如我们需要序列化一组对象并存储到磁盘中,还没有序列化完,中途磁盘满了,这时还没有全部序列化完,不能存储到磁盘中,这时需要把之前已经序列化的对象进行回滚(清空并丢弃它们),正确的方式如下:
public void SerialzeObject(FileStream fs,IFormatter formatter,Object rootObj){
int beforeSerialization=fs.Position; //保存文件的当前位置
try{
formatter.Serialize(fs,rootObj) //将包含一组对象的流序列化
}
catch{
fs.Position=beforeSerialization; //将文件流恢复到原来没序列化时的状态
fs.SetLength(fs.Position); //截断文件
throw; //往上一级抛
}
}
4 捕捉到异常后,可以根据需求自己重新new一个异常实例并往上抛
public string GetStream(string name){
FileStream fs=null;
try{
fs=new FileStream(name,FileMode.Open);
//其它业务逻辑操作
}
catch(FileNotFoundException e){
throw new Exception("文件路径不存在"+e.Message);
}
finally{
if(fs!=null) fs.Close();
}
}
注意:上述代码没有用IDE调试过,有可能会出现一些小错误
上述代码参考 CLR via C#(第三版)
参考文章:NET中异常处理的最佳实践 https://blog.csdn.net/jiankunking/article/details/43936729