指南针读取万分,判空操作的一点见识

图片 1

随着C#语言最新标准的出炉,现在它也提供了对可空类型的支持。这个小变化将会在处理那些包括可选项的数据库记录时非常有用。当然在其他地方,它也是非常有用的。

在 Java 开发中,NullPointerException
可以说是第一大异常了,不仅参数可能为空,网络请求,IO
加载,数据库查询的数据都可能为空,如果我们直接使用空的引用,就会有
NullPointerException 异常了。

intFind(carsListcars,LinkQueueCarque,CStringe){carsListp=cars-next;QueueNode*q=que.front-next;CStringstr;while(p!=NULL){CStringstr(p-carNumber);if(e==str)return1;p=p-next;str.Empty();}while(q!=NULL){CStringstr(q-carNumber);if(e==str)return1;q=q-next;str.Empty();}return0;}

简单说来,可空数据类型就是包含了所定义的数据类型或者值的空(null)的类型。C#的ECMA-334标准提供了对所有C#值类型的可空版本的描述。

但是,有些初学者可能很疑惑,我到底应该什么时候做判空操作,判空操作的一些准则是什么?其实我也是初学者,只是随着开发时间的增加,对判空的有了比初学时多的一点点的理解,在这里记录下来,希望可以帮到别人,同样让自己记忆更加深刻。

我这个while循环是在p非空的情况下才会进入循环体,为何会有这种空指针的现象?

定义可空类型

关于空指针异常

其实并不是每次使用一个空引用时都会发生异常,发生异常时都是我们真正去使用这个引用指向的对象时才会抛出空指针异常。看两个例子:

eg:

public String getString(){
    return null;
}

public int getInt(String str){
    return str.length();
}

String str = getString(); // 不会抛出异常
int index = getString(str); // 会抛出 NullPointerException 异常

上面这个例子中很直观的体现了空指针什么时候会发生,

getString(); 方法直接返回了 null,我们为 str 引用赋值为
null,是不会发生异常的,原因是我们直接使用了引用,并没有使用引用具体指向的对象,引用在栈内存中,是可以使用的。

getInt(String str); 方法中使用 str.length();
时,发生了异常,原因为我们此时真正使用的是 str
引用指向的对象在堆中的地址或者常量池中的地址,因为该引用指向的是 null
,所以此时会抛出空指针异常。

定义可空类型和非可空类型基本类似,不同的是采用了?来表示。如定义一个整型,你可以使用简单的语句:

判空操作

有关判空操作,并不是每次使用一个对象时都要去判空。如果我们确定一个对象不为空,这时候就不用判空,如果出现空指针说明使我们的代码设计问题,是需要修改编程策略去解决问题,不能直接加判空来实现。

还有一种情况是,我们的数据是别的地方传来的,这时候我们就需要做判断了,接下来就说这种情况下如何判空。

int myInt = 1;

判空时机

第一种情况是我们在一个方法中通过传参数或者拿别的引用,赋值给另外一个引用,这时候是不需要进行判空操作的,除非我们确定如果这步为空时对接下来的逻辑是起决定性作用的,比如如果这个参数为空,接下来的操作都不需要做,直接返回,这时候需要判空

第二种情况是我们确实要使用这个参数或者别的地方得到的引用指向的内存地址中的对象,这时候,我们就必须要做判空操作了,因为这时候为空时不但会引起程序的
crash
,还会影响我们对空对象是的处理逻辑,这时候判空,根据是否为空来做具体操作。

为了使得myInt能够存储一个空值,你可以这样声明它:

int? myNullableInt = 1;

你可以看到,这两个变量看上去好像是一样的。但是,可空类型的版本是非常不同的。可空的版本事实上是一个结构,它将值类型和一个标记该值是否为空的标志位结合在一起。一个可空类型有两个公共可读的属性,HasValue和value。如果存储了一个值那么HasValue这个布尔型变量就为true。否则,如果变量是空值就是false。如果HasValue是true,你可以获取这个变量的值。如下有两个对可空变量的有效赋值:

double? myDouble = 3.1415926;
double? myOtherDouble = null;

你可以看到,myDouble被赋值了,但是也可以被赋为空。在第二个语句里,myOtherDouble被初始化一个空值,这在一个非可空类型里不能这样做的。

使用可空类型

可空类型可以像普通值类型一样的使用。事实上,可以使用内建的隐式转换来转换相同类型的可空变量和非可空变量。这意味着你可以在一个标准整型和可空整型之间相互转换:

int? nFirst = null;
int Second = 2;

nFirst = Second; // 有效
nFirst = 123; // 有效
Second = nFirst; // 同样有效

nFirst = null; // 有效
Second = nFirst; // 例外,后者是非空类型

在以上的语句里,你可以看到如果可空变量不包含空值的话是可以和非可空变量交换值的。如果它是一个空值,那么就会抛出例外。为了防止例外,你可以使用可空变量的HasValue属性:

if (nFirst.HasValue) Second = nFirst;

你可以看到,如果nFirst有值赋值就会发生,否则程序会跳过此句语句。

使用可空类型的操作符

虽然可以使用相同值类型的可空和非可空变量的转换,也必须对操作符进行一些改变使得它们可以处理可空和非可空值。这些操作符被称为提升的操作符。

考虑如下代码:

int ValA = 10;
int? ValB = 3;

int? ValC = ValA * ValB;

在ValC里存储了什么?ValC中存储了30。标准操作符被扩展使得它们能够处理可空类型。考虑到如下的变化:

int ValA = 10;
int? ValB = null;

int? ValC = ValA * ValB;

ValC这次值为多少?ValC为空。无论哪个操作数为空,提升的操作符的结果为空。即使进行加法或减法,结果也为空。

如果ValC不为可空类型呢?如下的代码会有什么样的结果?

int ValA = 10;
int? ValB = null;

int ValC = ValA * ValB; // ValC 不为可空类型

代码将会抛出一个异常。ValA*ValB结果为空,但是不能赋值为非可空类型,这将会导致程序异常的抛出。
**      比较

**  比较将会和数学计算操作类似的方式处理。比较的操作数将同时被提升为可空的。这样就可以比较了,如果某个操作数为空,那么比较结果为false。

如果对比是否相等,两个同为空的变量将被认为是相等的。一个空变量和其他任意值的变量相比的结果是不相等。下面是一些比较的例子:

int abc = 123;
int xyz = 890;
int? def = null;
int? uvw = 123;

Comparison Result
abc == xyz // false
abc == def // false
def == null // true
abc == uvw // true
uvw == null // false
uvw != null // true

在所有的比较中,结果都是布尔型值true或者false。在做大小比较的时候,如果操作数的任意一个或者都是空值,那么结果返回的是false。如下展示了一些例子:

Comparison Result
abc > uvw // false, they are equal
abc < def // false, def is null
uvw < def // false, because def is null
def > null // false, because right side is null
uvw > null // false, because right side is null

可空性的移去

C#在新版本中加入了一个新的操作符,它被称为空接合操作符,使用如下的格式:

returnValue = first second;

这样,如果first不为空,那么它的值将返回作为returnValue的值。如果first为空,那么second的值将被返回。注意:returnValue可以为可空变量或者非可空变量。

如果你希望可空变量的值到一个非可空的版本,你可以这样做:

int? ValA= 123;
int? ValB = null;

int NewVarA = ValA ?? -1;
int NewVarB = ValB ?? -1;

NewVarA的值将会为123因为ValA不是空值。NewVarb的值是-1因为ValB是空值。你看一看到,这里你将可以将变量从一个空值转化成一个缺省值。这里缺省值是-1。

结束语

总得来说,最新的C#允许一个可空类型的存在。语言内部建立了对可空类型的处理机制。可空类型使得数据库记录和其他可选信息更加的容易处理。

可空类型是C#
ECMA-334版本的一个特性。你需要一个支持这个版本的C#的编译器。Visual
Studio 2005支持这个版本。