可空类型 C#Word格式.docx
《可空类型 C#Word格式.docx》由会员分享,可在线阅读,更多相关《可空类型 C#Word格式.docx(10页珍藏版)》请在冰豆网上搜索。
![可空类型 C#Word格式.docx](https://file1.bdocx.com/fileroot1/2023-1/2/5d53166a-a9ee-4233-add9-a11ae62f4fb3/5d53166a-a9ee-4233-add9-a11ae62f4fb31.gif)
如果nullableInt是一个int类型的变量,上面的代码是不能编译的。
前面的赋值等价于:
nullableInt=newSystem.Nullable();
与其他变量一样,无论是初始化为null(使用上面的语法),还是通过给它赋值来初始化,都不能在初始化之前使用它。
可以像测试引用类型一样,测试可空类型,看看它们是否为null:
if(nullableInt==null)
{
...
}
另外,可以使用HasValue属性:
if(nullableInt.HasValue)
这不适用于引用类型,即使引用类型有一个HasValue属性,也不能使用这种方法,因为引用类型的变量值为null,就表示不存在对象,当然就不能通过对象来访问这个属性,此时会抛出一个异常。
使用Value属性可以查看引用类型的值。
如果HasValue是true,就说明Value属性有一个非空值。
但如果HasValue是false,就说明变量被赋予了null,访问Value属性会抛出System.InvalidOperationException类型的异常。
可空类型要注意的一点是,它们非常有用,以致于修改了C#语法。
上面可空类型的变量不使用上述语法,而是使用下面的语法:
int?
nullableInt;
int?
是System.Nullable<
int>
的缩写,但可读性更高。
在后面的章节中就使用这个语法。
1.运算符和可空类型
对于简单类型如int,可以使用+、–等运算符来处理值。
而对于可空类型,这是没有区别的:
包含在可空类型中的值会隐式转换为需要的类型,使用适当的运算符。
这也适用于结构和自己提供的运算符。
op1=5;
result=op1*2;
注意其中result变量的类型也是int?
。
下面的代码不会编译:
intresult=op1*2;
为了使上面的代码正常工作,必须进行显式转换:
intresult=(int)op1*2;
只要op1有一个值,上面的代码就可以正常运行,如果op1是null,就会生成System.InvalidOperationException类型的异常。
这就引出了下一个问题:
当运算等式中的一个或两个值是null时,例如上面代码中的op1,会发生什么情况?
答案是:
对于除了bool?
之外的所有简单可空类型,该操作的结果是null,可以把它解释为“不能计算”。
对于结构,可以定义自己的运算符来处理这种情况(详见本章后面的内容)。
对于bool?
,为&
和|定义的运算符会得到非空返回值,如表12-1所示。
表
12-1
op1
op2
op1&
op2
op1|op2
true
false
null
这些运算符的结果与我们想像的一样,如果不需要知道其中一个操作数的值,就可以计算出结果,则该操作数是否为null就不重要。
2.?
?
运算符
为了进一步减少处理可空类型所需的代码量,使可空变量的处理变得更简单,可以使用?
运算符。
这个运算符允许提供可空类型是null和不是null时的默认值,其用法如下:
op1=null;
intresult=op1*2?
5;
在这个示例中,op1是null,所以op1*2也是null。
但是,?
运算符检测到这个情况,并把值5赋予result。
这里特别要注意,在结果中放入int类型的变量result不需要显式转换。
运算符会自动处理这个转换。
可以把?
等式的结果放在int?
中:
result=op1*2?
在处理可空变量时,?
运算符有许多用途,它也是提供默认值的一种方便方式,不需要使用if结构中的代码块。
在下面的示例中,将介绍可空类型Vector。
试试看:
可空类型
(1)在目录C:
\BegVCSharp\Chapter12下创建一个新控制台应用程序项目Ch12Ex01。
(2)使用VS快捷方式,在文件Vector.cs中添加一个新类Vector。
(3)修改Vector.cs中的代码,如下所示:
publicclassVector
publicdouble?
R=null;
Theta=null;
ThetaRadians
{
get
//Convertdegreestoradians.
return(Theta*Math.PI/180.0);
}
publicVector(double?
r,double?
theta)
//Normalize.
if(r<
0)
r=-r;
theta+=180;
theta=theta%360;
//Assignfields.
R=r;
Theta=theta;
publicstaticVectoroperator+(Vectorop1,Vectorop2)
try
//Get(x,y)coordinatesfornewvector.
doublenewX=op1.R.Value*Math.Sin(op1.ThetaRadians.Value)
+op2.R.Value*Math.Sin(op2.ThetaRadians.Value);
doublenewY=op1.R.Value*Math.Cos(op1.ThetaRadians.Value)
+op2.R.Value*Math.Cos(op2.ThetaRadians.Value);
//Convertto(r,theta).
doublenewR=Math.Sqrt(newX*newX+newY*newY);
doublenewTheta=Math.Atan2(newX,newY)*180.0/Math.PI;
//Returnresult.
returnnewVector(newR,newTheta);
catch
//Return"
null"
vector.
returnnewVector(null,null);
publicstaticVectoroperator-(Vectorop1)
returnnewVector(-op1.R,op1.Theta);
publicstaticVectoroperator-(Vectorop1,Vectorop2)
returnop1+(-op2);
publicoverridestringToString()
//Getstringrepresentationofcoordinates.
stringrString=R.HasValue?
R.ToString():
"
;
stringthetaString=Theta.HasValue?
Theta.ToString():
//Return(r,theta)string.
returnstring.Format("
({0},{1})"
rString,thetaString);
(4)修改Program.cs中的代码,如下所示:
classProgram
publicstaticvoidMain(string[]args)
Vectorv1=GetVector("
vector1"
);
Vectorv2=GetVector("
Console.WriteLine("
{0}+{1}={2}"
v1,v2,v1+v2);
{0}-{1}={2}"
v1,v2,v1-v2);
Console.ReadKey();
publicstaticVectorGetVector(stringname)
Input{0}magnitude:
"
name);
double?
r=GetNullableDouble();
Input{0}angle(indegrees):
theta=GetNullableDouble();
returnnewVector(r,theta);
publicstaticdouble?
GetNullableDouble()
result;
stringuserInput=Console.ReadLine();
result=double.Parse(userInput);
result=null;
returnresult;
(5)执行应用程序,给两个矢量(vector)输入值,结果如图12-1所示。
图12-1
(6)再次执行应用程序,这次跳过四个值中的至少一个,结果如图12-2所示。
图12-2
示例的说明
在这个示例中,创建了一个类Vector,它表示带极坐标(有一个幅值和一个角度)的矢量,如图12-3所示。
图12-3
坐标r和_在代码中用公共字段R和Theta表示,其中Theta的单位是度(°
)。
ThetaRad用于获取Theta的弧度值,这是必须的,因为Math类在其静态方法中使用弧度。
R和Theta的类型都是double?
,所以它们可以为空。
Vector的构造函数标准化R和Theta的初始值,然后赋予公共字段。
Vector类的主要功能是使用运算符重载对矢量进行相加和相减,这需要一些非常基本的三角函数知识,这里不解释它们。
在代码中,重要的是,如果在获取R或ThetaRad的Value属性时抛出了异常,即其中一个是null,就返回“空”矢量。
如果组成矢量的坐标是null,该矢量就是无效的,这里用R和Theta都可为null的Vector类来表示。
Vector类的其他代码重写了其他运算符,把相加的功能扩展到相减上,再重写ToString(),获取Vector对象的字符串表示。
Program.cs中的代码测试Vector类,让用户初始化两个矢量,再对它们进行相加和相减。
如果用户省略了一个值,该值就解释为null,应用前面提及的规则。