您的位置:首页 > 编程语言 > C#

C# in depth ( 第四章 可空类型)

2015-08-06 11:24 302 查看
4.1没有值时怎么办

想为DateTime变量设为null,但编译器不允许 (一个商品还没有卖出,则没有购买日期)

4.1.1为什么值类型的变量不能为null

对于引用类型的变量来说,其值是一个引用,而值类型变量的值是它本身的真实数据。可以认为,一个非空引用值提供了访问一个对象的途径。然而,null相当于一个特殊的值,它意味着我不引用任何对象。

4.1.2 C#1.0中表示空值的模式

魔值 (DateTime.MinValue)

引用类型包装

额外的布尔标志

4.2 System.Nullable<T>和System.Nullable

静态类System.Nuallable提供了一些工具方法,可以简化可空类型的使用。

4.2.1Nullable<T>简介

Nullable<Nullable<int>>是不允许的,即使Nullable<T>在其他方面符合值类型的一切特征。对于任何具体的可空类型来说,T的类型称为可空类型的基础类型(underlying type)。例如,Nullable<int>的基础类型就是int。

Nullable<T> 的HasValue 和Value属性。 如果在一个Nullable的HasValue属性是false的前提下,读取其Value值会报InvalidOperationException。

Nullable<T>有两个构造函数,默认构造函数创建“一个没有值的实例”。另一个构造函数则接受T的一个实例作为值。实例一经创建就是“不易变”的。

class NullableMembers
{
static void Display(Nullable<int> x)
{
Console.WriteLine("HasValue: {0}", x.HasValue);
if (x.HasValue)
{
Console.WriteLine("Value: {0}", x.Value);
Console.WriteLine("Explicit conversion: {0}", (int)x);
}
Console.WriteLine("GetValueOrDefault(): {0}",
x.GetValueOrDefault());
Console.WriteLine("GetValueOrDefault(10): {0}",
x.GetValueOrDefault(10));//如果这个nullable本身HasValue,就返回这个Value,如果没有Value就返回Default 此处为10
Console.WriteLine("ToString(): \"{0}\"", x.ToString());
Console.WriteLine("GetHashCode(): {0}", x.GetHashCode());
Console.WriteLine();
}

static void Main()
{
Nullable<int> x = 5;
x = new Nullable<int>(5);
Console.WriteLine("Instance with value:");
Display(x);

x = new Nullable<int>();
Console.WriteLine("Instance without value:");
Display(x);
}
}


int 可以隐式的转换为 nullable<int>, nullable<int>可以显式的转换为int (如果nullable<int>没有值,则转换失败,报InvalidOpreationException。

4.2.2 Nullable<T>装箱和拆箱

Nullable<T>的实例要么装箱成空引用(如果没有值),要么装箱成T的一个已装箱的值(如果有值).它永远不会被装箱成“装箱的可空int",因为不存在这种类型。

已装箱的值可以拆箱成普通类型,或拆箱成对应的可空类型。(要么拆箱成T,要么拆箱成Nullable<T>。拆箱一个空引用时,如果拆箱成普通类型,会抛出一个NullReferenceException;但如果拆箱成恰当的可空类型,就会拆箱成没有值的一个实例

class BoxingAndUnboxing
{
static void Main()
{
Nullable<int> nullable = 5;

object boxed = nullable;
Console.WriteLine(boxed.GetType()); //System.Int32, 因为Nullable<int>是HasValue的,所以装箱是对int进行装箱,所以GetType返回的是Int32

int normal = (int)boxed;
Console.WriteLine(normal);//5, 拆箱直接拆回int类型,然后会调用到int的toString()方法

nullable = (Nullable<int>)boxed;
Console.WriteLine(nullable);//5, 拆箱返回Nullable<int>型,然后调用Nullable的Tostring()方法,因为HasValue是true,最后调用Int的ToString方法。

nullable = new Nullable<int>();
boxed = nullable;
Console.WriteLine(boxed == null);//true,因为Nullable<int>的HasValue是False,所以会被装箱成null。

nullable = (Nullable<int>)boxed;
Console.WriteLine(nullable.HasValue);//false,因为是直接拆箱成Nullable,即使boxed是null也不会报错,最后拆箱成一个HasValue为false的Nullable<int>
}
}


4.2.3 Nullable<T>实例的相等性

Nullable<T>覆盖了object.Equals(object),但没有引入任何相等性操作符,也没有提供Equals(Nullable<T>)方法

调用first.Equals(second)的具体规划如下。

如果first没有值,second为null,它们就是相等的

如果first没有值, second不为null,它们就是不相等的

如果first有值,second为null,它们就是不相等的;

否则,如果first的值等于second,它们就是相等的。

4.2.4来自非泛型nullable类的支持

4.3 C#2.0为可空类型提供的语法糖

4.3.1 ?修饰符

class SyntacticSugar
{
static void Main()
{
int? nullable = 5;

object boxed = nullable;
Console.WriteLine(boxed.GetType());

int normal = (int)boxed;
Console.WriteLine(normal);

nullable = (int?)boxed;
Console.WriteLine(nullable);

nullable = new int?();
boxed = nullable;
Console.WriteLine(boxed == null);

nullable = (int?)boxed;
Console.WriteLine(nullable.HasValue);
}
}


4.3.2使用null进行赋值和比较

class AgeCalculation
{
class Person
{
DateTime birth;
DateTime? death;
string name;

public TimeSpan Age
{
get
{
if (death == null)
{
return DateTime.Now - birth;
}
else
{
return death.Value - birth;
}
}
}

public Person(string name,
DateTime birth,
DateTime? death)
{
this.birth = birth;
this.death = death;
this.name = name;
}
}

static void Main()
{
Person turing = new Person("Alan Turing",
new DateTime(1912, 6, 23),
new DateTime(1954, 6, 7));
Person knuth = new Person("Donald Knuth",
new DateTime(1938, 1, 10),
null);
}
}


4.3.3 可空转换和操作符

假如一个非可空的值类型支持一个操作符或者一种转换,而且那个操作符或者转换只涉及其他非可空的值类型时,那么可空的值类型也支持相同的操作符或转换,并且通常是将非可空的值类型转换成它们的可空等价物 比如int到long存在着一个隐式转换,就意味着int?到long?也存在着一个隐式的转换。

涉及可空类型的转换

null到T?的隐式转换;

T到T?的隐式转换;

T?到T的显示转换。

4.3.4 可空逻辑 (P108 表4-2)

4.3.5 对可空类型使用as操作符

在C#2.0之前,as操作符只能用于引用类型。而在C#2.0中,它也可以用于可空类型。 其结果为可空类型的某个值或空值(如果原始引用为错误类型或空)或有意义的值。

static void PrintValueAsInt32(object o)
{
int? nullable = o as int?;
Console.WriteLine(nullable.HasValue ? nullable.Value.ToString() : "null");
}

PrintValueAsInt32(5);
PrintValueAsInt32("some string");


使用is和强制转换要比使用as操作符快20倍!!!

4.3.6 空合并操作符

first ?? second

对first进行求值

如果结果非空,则该结果就是整个表达式的结果;

否则求second的值,其结果作为整个表达式的结果。

并非只能用于可空类型,还能应用于引用类型。

4.4 可空类型的新奇用法

4.4.1尝试一个不使用输出参数的操作

class NullableTryParse
{
static int? TryParse(string data)
{
int ret;
if (int.TryParse(data, out ret))
{
return ret;
}
else
{
return null;
}
}

static void Main()
{
int? parsed = TryParse("Not valid");
if (parsed != null)
{
Console.WriteLine("Parsed to {0}", parsed.Value);
}
else
{
Console.WriteLine("Couldn't parse");
}
}
}


4.4.2 空合并操作符让比较不再痛苦
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: