C#中的异常处理
1 | try |
如果一个try抛出异常,但是没有对应的catch处理程序,那么这个方法将立即退出,并返回它的调用方法,如果它的调用方法没有使用try,或者没有找到匹配的catch,那个调用也会退出,返回更上一层。由内向外遍历了所有调用方法之后,假如找不到一个相匹配的catch处理程序,整个程序会终止。
一个异常发生之后,将运行第一个匹配的异常处理程序。
checked和unchecked整数运算
默认情况下C#允许计算悄悄溢出,如果需要,可以启用溢出检查。1
2
3
4
5
6//在checked关键字开头的下面代码块中,任何整数运算溢出,都会抛出一个OverflowException,只会检查代码块中的溢出,如果块中出现方法调用,不会对调用的方法进行检查。
checked
{
int willThow = number++;
Console.WriteLine("sss");
}
unchecked相反,在unchecked块中的语句永远不检查。
finally块
1 | try |
finally块中的语句一定会执行,一般用于释放资源。
C#小技巧
1 | namespace Classes |
可以把任务封装至静态方法dowork,即可捕捉所有异常。
匿名类
1 | var anonymousObject = new(Name = "123", Age = 44); |
这个类包含两个Public字段,分别为Name和Age,编译器会根据数据类型进行推断。定义一个匿名类,编译器会为这个类生成一个自己才知道的名称。匿名类只能包含public字段,字段必须全部初始化,而且不能在其中指定方法。
C#中的值类型和引用类型
值类型分配内存,引用类型分配地址指向内存,默认传参对象是引用(地址)。
C#中的可空类型
对于值类型,利用C#定义的一个修饰符,将一个变量声明为可空类型。1
2
3
4
5int? i = null; //声明一个可空类型
int j = 99;
int i = 1;
int i = j; //可以将具有恰当形式的表达式赋值给可空类型
j = i; //不可以将一个可空的值赋值给一个普通的值
ref和out
如果一个参数附加了ref关键字前缀,该参数就会成为实参别名,而不是副本。实参也必须附加ref,使用ref前必须对参数进行初始化。1
2
3
4
5
6
7
8
9static void Inc(ref int param)
{
param++;
}
static void Main()
{
int arg = 42;
Inc(ref arg);
}
out关键字与ref类似,向参数的任何操作也会同时应用于实参,out是对output的简称,在传递一个out参数后,必须在方法内部对其赋值。
C#中的装箱
object类是所有类型的基类1
2int i = 2;
object o = i;
对于C#来说,一个应用类型都必须引用堆上的数据,在上代码第二行,引用了栈上的i,其实是引用了i在堆上的副本,这种操作为装箱。
C#中的拆箱
1 | object o = 42; |
一个值类型转化为obj类型,那么需要进行强制类型转化,将自动检查obj中的实际类型,不符合会抛出异常。
is操作符
可以用is操作符验证对象类型:1
2
3
4
5object o = 42;
if(o is int)
{
int i = (int)o;
}
为了代码的健壮性,在强制类型转换之前可以先判断是否是所需要的类型。
as操作符
1 | object o = 42; |
C#中的指针
指针的管理很容易出问题,C#通过引用来解决,如果要使用指针,必须将代码标记为unsafe(不安全)1
2
3
4unsafe
{
}