开发软件过程中,为了防止程序崩溃出错都会用 try ... catch 包裹住会产生异常的代码。随着项目越来越大,try ... catch 语句到处都是,令人眼花的花括号,丑陋无比的缩进让人崩溃。
IO 操作通常最容易引发异常,文件读写网络访问数据库操作这些,比如读取当前目录的文本:
string text = System.IO.File.ReadAllText("demo.txt");
Console.WriteLine(text);
IO 异常
这时就需要在外层用 try ... catch 将这两行代码包括起来,并提示错误:
try
{
string text = System.IO.File.ReadAllText("demo.txt");
Console.WriteLine(text);
}
catch (System.IO.IOException ex)
{
Console.WriteLine(ex.Message);
}
为了简化上面的代码结构,在这里我们可以设计一个静态方法,将需要执行的代码作为参数,在 try ... catch 里执行它。如何将要执行的代码作为参数传给另外一个方法呢,我们可以用 Action<T> 和 Fun<T> 委托,他们一个是无返回参数,一个是有返回参数。
public static void Try(Action act, Action<Exception> errorCallback = null)
{
try
{
act();
}
catch (Exception ex)
{
errorCallback?.Invoke(ex);
}
}
这个 Try 方法接受两个委托作为参数,第一个是要执行的代码,第二个是出现了异常也好返回一个 Exception 类型给调用方,并且它是一个可为 null 类型的参数,也就是可选参数。
把这个方法放到一个静态类 TryCatch 里,在调用的类使用 using 语句使用这个静态类,没错,C# 6 就是这么叼。
using static TryCatch;
改造后的语句:
string text = "";
Try(() =>
{
text = System.IO.File.ReadAllText("demo.txt");
}, error =>
{
WriteLine(error.Message);
});
这里就很厉害了,代码竟然没有变短反而变长了和更难理解了。
继续改造,使用 Func<T>:
public static T Try<T>(Func<T> func, Func<Exception, T> errorCallback = null)
{
try
{
return func();
}
catch (Exception ex)
{
if (errorCallback != null)
{
return errorCallback(ex);
}
return default(T);
}
}
再继续改造刚才的代码:
string text = Try(()=> { return System.IO.File.ReadAllText("demo.txt"); });
WriteLine(text);
震惊!某知名函数竟然不报错,原因竟然是这:
return default(T);
很好理解,就是返回默认值了。
可以在那两个静态类里加入 logger,这样每一个 try ... catch 报错都可以记录下来,同理还可以对实现了 IDispose 接口的类封装,省略 using 代码块。
网友评论