- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章关于.NET异常处理的思考总结由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
年关将至,对于大部分程序员来说,马上就可以闲下来一段时间了,然而在这个闲暇的时间里,唯有争论哪门语言更好可以消磨时光,估计最近会有很多关于java与.net的博文出现,我表示要作为一个吃瓜群众,静静的看着大佬们发表心情.
以上的废话说的够多了,这里就不再废话了,还是切入正题吧.
在项目开发中,对于系统和代码的稳定性和容错性都是有对应的要求。实际开发项目中的代码与样例代码的区别,更多的是在代码的运行的稳定性、容错性、扩展性的比较。因为对于实现一个功能来说,实现功能的核心代码是一样的,可能只是在写法上优化而已,但是在实现某一个操作上使用的类来说,这一点是绝大多数时候是一样的。这样看来,我们在实际开发的过程中,需要考虑的问题比较多,已经不仅仅局限于某一具体的功能实现,更多的是代码的稳定性和扩展性考虑.
以上是在实际开发中需要面对的问题,笔者在最近的博文中,也在考虑这个异常到底需要怎么去写,以及异常到底需要怎么去理解,希望对大家有一个帮助,也欢迎大家提出自己的想法和意见,分享自己的知识和见解.
一.DotNET异常的概述:
谈到异常,我们就需要知道什么叫做异常,万事万物如果我们想去学习,就应该知道我们要学习的东西是什么,这样在心里也好有一个大概的认知。异常是指成员没有完成它的名称宣称可以完成的行动。在.NET中,构造器、获取和设置属性、添加和删除事件、调用操作符重载和调用转换操作符等等都没有办法返回错误代码,但是在这些构造中又需要报告错误,那就必须提供异常处理机制.
在异常的处理中,我们经常使用到的三个块分别是:try块;catch块;finally块。这三个块可以一起使用,也可以不写catch块使用,异常处理块可以嵌套使用,具体的方法在下面会介绍到.
在异常的处理机制中,一般有三种选择:重新抛出相同的异常,向调用栈高一层的代码通知该异常的发生;抛出一个不同的异常,想调用栈高一层代码提供更丰富的异常信息;让线程从catch块的底部退出。 。
有关异常的处理方式,有一些指导性的建议.
1.恰当的使用finally块:
finally块可以保证不管线程抛出什么类型的异常都可以被执行,finall块一般用来做清理那些已经成功启动的操作,然后再返回调用者或者finally块之后的代码.
2.异常捕捉需适当:
为什么要适当的捕捉异常呢?如下代码,因为我们不能什么异常都去捕捉,在捕获异常后,我们需要去处理这些异常,如果我们将所有的异常都捕捉后,但是没有预见会发生的异常,我们就没有办法去处理这些异常.
如果应用程序代码抛出一个异常,应用程序的另一端则可能预期要捕捉这个异常,因此不能写成一个”大小通吃“的异常块,应该允许该异常在调用栈中向上移动,让应用程序代码针对性地处理这个异常.
在catch块中,可以使用System.Exception捕捉异常,但是最好在catch块末尾重新抛出异常。至于原因在后面会讲解到.
1
2
3
4
5
6
7
8
9
10
11
12
|
try
{
var hkml = GetRegistryKey(rootKey);
var subkey = hkml.CreateSubKey(subKey);
if
(subkey !=
null
&& keyName !=
string
.Empty)
subkey.SetValue(keyName, keyValue, RegistryValueKind.String);
}
catch
(Exception ex)
{
Log4Helper.Error(
"创建注册表错误"
+ ex);
throw
new
Exception(ex.Message,ex);
}
|
3.从异常中恢复:
我们在捕获异常后,可以针对性的写一些异常恢复的代码,可以让程序继续运行。在捕获异常时,需要捕获具体的异常,充分的掌握在什么情况下会抛出异常,并知道从捕获的异常类型派生出了那些类型。除非在catch块的末尾重新抛出异常,否则不要处理或捕获System.Exception异常.
4.维持状态:
一般情况下,我们完成一个操作或者一个方法时,需要调用几个方法组合完成,在执行的过程中会出现前面几个方法完成,后面的方法发生异常。发生不可恢复的异常时回滚部分完成的操作,因为我们需要恢复信息,所有我们在捕获异常时,需要捕获所有的异常信息.
5.隐藏实现细节来维持契约:
有时可能需要捕捉一个异常并重新抛出一个不同的异常,这样可以维系方法的契约,抛出的心异常类型地应该是一个具体的异常。看如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
FileStream fs =
null
;
try
{
fs = FileStream();
}
catch
(FileNotFoundException e)
{
//抛出一个不同的异常,将异常信息包含在其中,并将原来的异常设置为内部异常
throw
new
NameNotFoundException();
}
catch
(IOException e)
{
//抛出一个不同的异常,将异常信息包含在其中,并将原来的异常设置为内部异常
throw
new
NameNotFoundException();
}
finally
{
if
(fs !=
null
)
{
fs.close();
}
}
|
以上的代码只是在说明一种处理方式。应该让抛出的所有异常都沿着方法的调用栈向上传递,而不是把他们”吞噬“了之后抛出一个新的异常。如果一个类型构造器抛出一个异常,而且该异常未在类型构造器方法中捕获,CLR就会在内部捕获该异常,并改为抛出一个新的TypeInitialztionException.
二.DotNET异常的常用处理机制:
在代码发生异常后,我们需要去处理这个异常,如果一个异常没有得到及时的处理,CLR会终止进程。在异常的处理中,我们可以在一个线程捕获异常,在另一个线程中重新抛出异常。异常抛出时,CLR会在调用栈中向上查找与抛出的异常类型匹配的catch块。如果没有任何catch块匹配抛出的异常类型,就发生一个未处理异常。CLR检测到进程中的任何线程有一个位处理异常,都会终止进程.
1.异常处理块:
(1).try块:包含代码通常需要执行一些通用的资源清理操作,或者需要从异常中恢复,或者两者都需要。try块还可以包含也许会抛出异常的代码。一个try块至少有一个关联的catch块或finall块。 。
(2).catch块:包含的是响应一个异常需要执行的代码。catch关键字后的圆括号中的表达式是捕获类型。捕获类型从System.Exception或者其派生类指定。CLR自上而下搜素一个匹配的catch块,所以应该教具体的异常放在顶部。一旦CLR找到一个具有匹配捕获类型的catch块,就会执行内层所有finally块中的代码,”内层finally“是指抛出异常的tey块开始,到匹配异常的catch块之间的所有finally块.
使用System.Exception捕捉异常后,可以采用在catch块的末尾重新抛出异常,因为如果我们在捕获Exception异常后,没有及时的处理或者终止程序,这一异常可能对程序造成很大的安全隐患,Exception类是所有异常的基类,可以捕获程序中所有的异常,如果出现较大的异常,我们没有及时的处理,造成的问题是巨大的.
(3).finally块:包含的代码是保证会执行的代码。finally块的所有代码执行完毕后,线程退出finally块,执行紧跟在finally块之后的语句。如果不存在finally块,线程将从最后一个catch块之后的语句开始执行.
备注:异常块可以组合和嵌套,对于三个异常块的样例,在这里就不做介绍,异常的嵌套可以防止在处理异常的时候再次出现未处理的异常,以上这些就不再赘述.
2.异常处理实例:
(1).异常处理扩展方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/// <summary>
/// 格式化异常消息
/// </summary>
/// <param name="e">异常对象</param>
/// <param name="isHideStackTrace">是否隐藏异常规模信息</param>
/// <returns>格式化后的异常信息字符串</returns>
public
static
string
FormatMessage(
this
Exception e,
bool
isHideStackTrace =
false
)
{
var sb =
new
StringBuilder();
var count = 0;
var appString =
string
.Empty;
while
(e !=
null
)
{
if
(count > 0)
{
appString +=
" "
;
}
sb.AppendLine(
string
.Format(
"{0}异常消息:{1}"
, appString, e.Message));
sb.AppendLine(
string
.Format(
"{0}异常类型:{1}"
, appString, e.GetType().FullName));
sb.AppendLine(
string
.Format(
"{0}异常方法:{1}"
, appString, (e.TargetSite ==
null
?
null
: e.TargetSite.Name)));
sb.AppendLine(
string
.Format(
"{0}异常源:{1}"
, appString, e.Source));
if
(!isHideStackTrace && e.StackTrace !=
null
)
{
sb.AppendLine(
string
.Format(
"{0}异常堆栈:{1}"
, appString, e.StackTrace));
}
if
(e.InnerException !=
null
)
{
sb.AppendLine(
string
.Format(
"{0}内部异常:"
, appString));
count++;
}
e = e.InnerException;
}
return
sb.ToString();
}
|
(2).验证异常:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
/// <summary>
/// 检查字符串是空的或空的,并抛出一个异常
/// </summary>
/// <param name="val">值测试</param>
/// <param name="paramName">参数检查名称</param>
public
static
void
CheckNullOrEmpty(
string
val,
string
paramName)
{
if
(
string
.IsNullOrEmpty(val))
throw
new
ArgumentNullException(paramName,
"Value can't be null or empty"
);
}
/// <summary>
/// 请检查参数不是空的或空的,并抛出异常
/// </summary>
/// <param name="param">检查值</param>
/// <param name="paramName">参数名称</param>
public
static
void
CheckNullParam(
string
param,
string
paramName)
{
if
(
string
.IsNullOrEmpty(param))
throw
new
ArgumentNullException(paramName, paramName +
" can't be neither null nor empty"
);
}
/// <summary>
/// 检查参数不是无效,并抛出一个异常
/// </summary>
/// <param name="param">检查值</param>
/// <param name="paramName">参数名称</param>
public
static
void
CheckNullParam(
object
param,
string
paramName)
{
if
(param ==
null
)
throw
new
ArgumentNullException(paramName, paramName +
" can't be null"
);
}
/// <summary>
/// 请检查参数1不同于参数2
/// </summary>
/// <param name="param1">值1测试</param>
/// <param name="param1Name">name of value 1</param>
/// <param name="param2">value 2 to test</param>
/// <param name="param2Name">name of vlaue 2</param>
public
static
void
CheckDifferentsParams(
object
param1,
string
param1Name,
object
param2,
string
param2Name)
{
if
(param1 == param2) {
throw
new
ArgumentException(param1Name +
" can't be the same as "
+ param2Name,
param1Name +
" and "
+ param2Name);
}
}
/// <summary>
/// 检查一个整数值是正的(0或更大)
/// </summary>
/// <param name="val">整数测试</param>
public
static
void
PositiveValue(
int
val)
{
if
(val < 0)
throw
new
ArgumentException(
"The value must be greater than or equal to 0."
);
}
|
(3).Try-Catch扩展操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
/// <summary>
/// 对某对象执行指定功能与后续功能,并处理异常情况
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="source">值</param>
/// <param name="action">要对值执行的主功能代码</param>
/// <param name="failureAction">catch中的功能代码</param>
/// <param name="successAction">主功能代码成功后执行的功能代码</param>
/// <returns>主功能代码是否顺利执行</returns>
public
static
bool
TryCatch<T>(
this
T source, Action<T> action, Action<Exception> failureAction,
Action<T> successAction) where T :
class
{
bool
result;
try
{
action(source);
successAction(source);
result =
true
;
}
catch
(Exception obj)
{
failureAction(obj);
result =
false
;
}
return
result;
}
/// <summary>
/// 对某对象执行指定功能,并处理异常情况
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="source">值</param>
/// <param name="action">要对值执行的主功能代码</param>
/// <param name="failureAction">catch中的功能代码</param>
/// <returns>主功能代码是否顺利执行</returns>
public
static
bool
TryCatch<T>(
this
T source, Action<T> action, Action<Exception> failureAction) where T :
class
{
return
source.TryCatch(action,
failureAction,
obj => { });
}
/// <summary>
/// 对某对象执行指定功能,并处理异常情况与返回值
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <typeparam name="TResult">返回值类型</typeparam>
/// <param name="source">值</param>
/// <param name="func">要对值执行的主功能代码</param>
/// <param name="failureAction">catch中的功能代码</param>
/// <param name="successAction">主功能代码成功后执行的功能代码</param>
/// <returns>功能代码的返回值,如果出现异常,则返回对象类型的默认值</returns>
public
static
TResult TryCatch<T, TResult>(
this
T source, Func<T, TResult> func, Action<Exception> failureAction,
Action<T> successAction)
where T :
class
{
TResult result;
try
{
var u = func(source);
successAction(source);
result = u;
}
catch
(Exception obj)
{
failureAction(obj);
result =
default
(TResult);
}
return
result;
}
/// <summary>
/// 对某对象执行指定功能,并处理异常情况与返回值
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <typeparam name="TResult">返回值类型</typeparam>
/// <param name="source">值</param>
/// <param name="func">要对值执行的主功能代码</param>
/// <param name="failureAction">catch中的功能代码</param>
/// <returns>功能代码的返回值,如果出现异常,则返回对象类型的默认值</returns>
public
static
TResult TryCatch<T, TResult>(
this
T source, Func<T, TResult> func, Action<Exception> failureAction)
where T :
class
{
return
source.TryCatch(func,
failureAction,
obj => { });
}
|
本文没有具体介绍try,catch,finally的使用,而是给出一些比较通用的方法,主要是一般的开发者对于三个块的使用都有一个认识,就不再做重复的介绍.
三.DotNET的Exception类分析:
CLR允许异常抛出任何类型的实例,这里我们介绍一个System.Exception类:
1.Message属性:指出抛出异常的原因.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
[__DynamicallyInvokable]
public
virtual
string
Message
{
[__DynamicallyInvokable]
get
{
if
(
this
._message !=
null
)
{
return
this
._message;
}
if
(
this
._className ==
null
)
{
this
._className =
this
.GetClassName();
}
return
Environment.GetRuntimeResourceString(
"Exception_WasThrown"
,
new
object
[] {
this
._className });
}
}
|
由以上的代码可以看出,Message只具有get属性,所以message是只读属性。GetClassName()获取异常的类。GetRuntimeResourceString()获取运行时资源字符串.
2.StackTrace属性:包含抛出异常之前调用过的所有方法的名称和签名.
1
2
3
4
5
6
7
8
9
|
public
static
string StackTrace
{
[SecuritySafeCritical]
get
{
new
EnvironmentPermission(PermissionState.Unrestricted).Demand();
return
GetStackTrace(
null
,
true
);
}
}
|
EnvironmentPermission()用于环境限制,PermissionState.Unrestricted设置权限状态,GetStackTrace()获取堆栈跟踪,具体看一下GetStackTrace()的代码.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
internal
static
string GetStackTrace(Exception e, bool needFileInfo)
{
StackTrace trace;
if
(e ==
null
)
{
trace =
new
StackTrace(needFileInfo);
}
else
{
trace =
new
StackTrace(e, needFileInfo);
}
return
trace.ToString(StackTrace.TraceFormat.Normal);
}
|
1
2
3
4
5
6
7
8
9
10
|
public
StackTrace(Exception e, bool fNeedFileInfo)
{
if
(e ==
null
)
{
throw
new
ArgumentNullException(
"e"
);
}
this
.m_iNumOfFrames =
0
;
this
.m_iMethodsToSkip =
0
;
this
.CaptureStackTrace(
0
, fNeedFileInfo,
null
, e);
}
|
以上是获取堆栈跟踪方法的具体实现,此方法主要用户调试的时候.
3.GetBaseException()获取基础异常信息方法.
1
2
3
4
5
6
7
8
9
10
11
12
|
[__DynamicallyInvokable]
public
virtual
Exception GetBaseException()
{
Exception innerException =
this
.InnerException;
Exception exception2 =
this
;
while
(innerException !=
null
)
{
exception2 = innerException;
innerException = innerException.InnerException;
}
return
exception2;
}
|
InnerException属性是内在异常,这是一个虚方法,在这里被重写。具体看一下InnerException属性.
1
2
3
4
5
6
7
8
9
|
[__DynamicallyInvokable]
public
Exception InnerException
{
[__DynamicallyInvokable, TargetedPatchingOptOut(
"Performance critical to inline this type of method across NGen image boundaries"
)]
get
{
return
this
._innerException;
}
}
|
4.ToString()将异常信息格式化.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
private
string
ToString(
bool
needFileLineInfo,
bool
needMessage)
{
string
className;
string
str = needMessage ?
this
.Message :
null
;
if
((str ==
null
) || (str.Length <= 0))
{
className =
this
.GetClassName();
}
else
{
className =
this
.GetClassName() +
": "
+ str;
}
if
(
this
._innerException !=
null
)
{
className = className +
" ---> "
+
this
._innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine +
" "
+ Environment.GetRuntimeResourceString(
"Exception_EndOfInnerExceptionStack"
);
}
string
stackTrace =
this
.GetStackTrace(needFileLineInfo);
if
(stackTrace !=
null
)
{
className = className + Environment.NewLine + stackTrace;
}
return
className;
}
|
在此方法中,将获取的异常信息进行格式化为字符串,this.GetClassName() 获取异常类的相关信息.
以上我们注意到[__DynamicallyInvokable]定制属性,我们看一下具体的实现代码:
1
2
3
4
|
[TargetedPatchingOptOut(
"Performance critical to inline this type of method across NGen image boundaries"
)]
public
__DynamicallyInvokableAttribute()
{
}
|
以上我们主要注释部分,”图像边界“这个属性的相关信息,请参见《Via CLR c#》,这里就不做具体的介绍.
四.总结:
以上在对异常的介绍中,主要介绍了CLR的异常处理机制,一些较为通用的异常代码,以及对Exception类的介绍。在实际的项目中,我们一般不要将异常直接抛出给客户,我们在编写程序时,已经考虑程序的容错性,在程序捕获到异常后,尽量去恢复程序,或者将异常信息写入日志,让程序进入错误页。如果出现比较严重的异常,最后将异常抛出,终止程序.
希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:http://www.cnblogs.com/pengze0902/p/6185952.html 。
最后此篇关于关于.NET异常处理的思考总结的文章就讲到这里了,如果你想了解更多关于关于.NET异常处理的思考总结的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
对于 Metal ,如果对主纹理进行 mipmap 处理,是否还需要对多采样纹理进行 mipmap 处理?我阅读了苹果文档,但没有得到任何相关信息。 最佳答案 Mipmapping 适用于您将从中
我正在使用的代码在后端 Groovy 代码中具有呈现 GSP(Groovy 服务器页面)的 Controller 。对于前端,我们使用 React-router v4 来处理路由。我遇到的问题是,通过
我们正在 build 一个巨大的网站。我们正在考虑是在服务器端(ASP .Net)还是在客户端进行 HTML 处理。 例如,我们有 HTML 文件,其作用类似于用于生成选项卡的模板。服务器端获取 HT
我正在尝试将图像加载到 void setup() 中的数组中,但是当我这样做时出现此错误:“类型不匹配,'processing .core.PImage' does not匹配“processing.
我正在尝试使用其私有(private)应用程序更新 Shopify 上的客户标签。我用 postman 尝试过,一切正常,但通过 AJAX,它带我成功回调而不是错误,但成功后我得到了身份验证链接,而不
如何更改我的 Processing appIconTest.exe 导出的默认图标在窗口中的应用程序? 默认一个: 最佳答案 经过一些研究,我能找到的最简单的解决方案是: 进入 ...\process
我在 Processing 中做了一个简单的小游戏,但需要一些帮助。我有一个 mp3,想将它添加到我的应用程序中,以便在后台循环运行。 这可能吗?非常感谢。 最佳答案 您可以使用声音库。处理已经自带
我有几个这样创建的按钮: 在 setup() PImage[] imgs1 = {loadImage("AREA1_1.png"),loadImage("AREA1_2.png"),loadImage
我正在尝试使用 Processing 创建一个多人游戏,但无法弄清楚如何将屏幕分成两个以显示玩家的不同情况? 就像在 c# 中一样,我们有Viewport leftViewport,rightView
我一直在尝试使用 Moore 邻域在处理过程中创建元胞自动机,到目前为止非常成功。我已经设法使基本系统正常工作,现在我希望通过添加不同的功能来使用它。现在,我检查细胞是否存活。如果是,我使用 fill
有没有办法用 JavaScript 代码检查资源使用情况?我可以检查脚本的 RAM 使用情况和 CPU 使用情况吗? 由于做某事有多种方法,我可能会使用不同的方法编写代码,并将其保存为两个不同的文件,
我想弄清楚如何处理这样的列表: [ [[4,6,7], [1,2,4,6]] , [[10,4,2,4], [1]] ] 这是一个整数列表的列表 我希望我的函数将此列表作为输入并返回列表中没有重复的整
有没有办法在不需要时处理 MethodChannel/EventChannel ?我问是因为我想为对象创建多个方法/事件 channel 。 例子: class Call { ... fields
我有一个关于在 Python3 中处理 ConnectionResetError 的问题。这通常发生在我使用 urllib.request.Request 函数时。我想知道如果我们遇到这样的错误是否可
我一直在努力解决这个问题几个小时,但无济于事。代码很简单,一个弹跳球(粒子)。将粒子的速度初始化为 (0, 0) 将使其保持上下弹跳。将粒子的初始化速度更改为 (0, 0.01) 或任何十进制浮点数都
我把自己弄得一团糟。 我想在我的系统中添加 python3.6 所以我决定在我的 Ubuntu 19.10 中卸载现有的。但是现在每次我想安装一些东西我都会得到这样的错误: dpkg: error w
我正在努力解决 Rpart 包中的 NA 功能。我得到了以下数据框(下面的代码) Outcome VarA VarB 1 1 1 0 2 1 1 1
我将 Java 与 JSF 一起使用,这是 Glassfish 3 容器。 在我的 Web 应用程序中,我试图实现一个文件(图像)管理系统。 我有一个 config.properties我从中读取上传
所以我一直在Processing工作几个星期以来,虽然我没有编程经验,但我已经转向更复杂的项目。我正在编写一个进化模拟器,它会产生具有随机属性的生物。 最终,我将添加复制,但现在这些生物只是在屏幕上漂
有人知道 Delphi 2009 对“with”的处理有什么不同吗? 我昨天解决了一个问题,只是将“with”解构为完整引用,如“with Datamodule、Dataset、MainForm”。
我是一名优秀的程序员,十分优秀!