我们在声明一个对象的时候习惯性把该对象声明为null,但是值类型呢,int需要声明为0,DateTime可以声明为DateTime.Now或者Default(DateTime),那么值类型可不可以声明为null呢?答案是可以的!这就是今天的主题,可空值类型。
可空值类型比较简单,先来看一下可空值类型的语法:
语法:
int? value=3;
上面这句话其实就声明了一个可空值类型value,并给该变量赋值3.
也可以这样写:
int? nullValue = null;
这样就可以给该int类型赋一个null值。
如果说要输出该可空值类型的值,应该怎么做呢?可以这样
Console.WriteLine(value.Value)
调用该变量的Value属性就可以得到该变量的值。
注意:
可空值类型就这么简单么?是的,它的语法就这么简单,使用起来也很方便,不过有些需要注意的地方,
static void Main(string[] args)
{
int? sum = Sum(23, null);
}
public static Int32? Sum(Int32? value, Int32? value1)
{
return value + value1;
}
这段代码的结果是什么?23?不对,结果是null(原因会在下来进行讲解)
以下是一些对可空值类型操作符的定义(来自Clr via c#):
为什么结果是null呢?让我们来剖析一下:
可空值类型内部剖析:
public static Int32? Sum(Int32? value, Int32? value1)
{
return value + value1;
}
让我们用ildasm来看一下这段代码的方法签名:
.method public hidebysig static valuetype [mscorlib]System.Nullable`1<int32>
Sum(valuetype [mscorlib]System.Nullable`1<int32> 'value',
valuetype [mscorlib]System.Nullable`1<int32> value1) cil managed
可以看到Int32?被编译成了Nullable<Int32>结构,
在VS中查看该结构的定义是这样的:
// Summary:
// Represents an object whose underlying type is a value type that can also
// be assigned null like a reference type.
//
// Type parameters:
// T:
// The underlying value type of the System.Nullable<T> generic type.
[Serializable]
[TypeDependency("System.Collections.Generic.NullableComparer`1")]
[TypeDependency("System.Collections.Generic.NullableEqualityComparer`1")]
public struct Nullable<T> where T : struct
{
//
// Summary:
// Initializes a new instance of the System.Nullable<T> structure to the specified
// value.
//
// Parameters:
// value:
// A value type.
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public Nullable(T value);
public static explicit operator T(T? value);
public static implicit operator T?(T value);
// Summary:
// Gets a value indicating whether the current System.Nullable<T> object has
// a value.
//
// Returns:
// true if the current System.Nullable<T> object has a value; false if the current
// System.Nullable<T> object has no value.
public bool HasValue { get; }
//
// Summary:
// Gets the value of the current System.Nullable<T> value.
//
// Returns:
// The value of the current System.Nullable<T> object if the System.Nullable<T>.HasValue
// property is true. An exception is thrown if the System.Nullable<T>.HasValue
// property is false.
//
// Exceptions:
// System.InvalidOperationException:
// The System.Nullable<T>.HasValue property is false.
public T Value { get; }
// Summary:
// Indicates whether the current System.Nullable<T> object is equal to a specified
// object.
//
// Parameters:
// other:
// An object.
//
// Returns:
// true if the other parameter is equal to the current System.Nullable<T> object;
// otherwise, false. This table describes how equality is defined for the compared
// values: Return ValueDescriptiontrueThe System.Nullable<T>.HasValue property
// is false, and the other parameter is null. That is, two null values are equal
// by definition.-or-The System.Nullable<T>.HasValue property is true, and the
// value returned by the System.Nullable<T>.Value property is equal to the other
// parameter.falseThe System.Nullable<T>.HasValue property for the current System.Nullable<T>
// structure is true, and the other parameter is null.-or-The System.Nullable<T>.HasValue
// property for the current System.Nullable<T> structure is false, and the other
// parameter is not null.-or-The System.Nullable<T>.HasValue property for the
// current System.Nullable<T> structure is true, and the value returned by the
// System.Nullable<T>.Value property is not equal to the other parameter.
public override bool Equals(object other);
//
// Summary:
// Retrieves the hash code of the object returned by the System.Nullable<T>.Value
// property.
//
// Returns:
// The hash code of the object returned by the System.Nullable<T>.Value property
// if the System.Nullable<T>.HasValue property is true, or zero if the System.Nullable<T>.HasValue
// property is false.
public override int GetHashCode();
//
// Summary:
// Retrieves the value of the current System.Nullable<T> object, or the object's
// default value.
//
// Returns:
// The value of the System.Nullable<T>.Value property if the System.Nullable<T>.HasValue
// property is true; otherwise, the default value of the current System.Nullable<T>
// object. The type of the default value is the type argument of the current
// System.Nullable<T> object, and the value of the default value consists solely
// of binary zeroes.
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public T GetValueOrDefault();
//
// Summary:
// Retrieves the value of the current System.Nullable<T> object, or the specified
// default value.
//
// Parameters:
// defaultValue:
// A value to return if the System.Nullable<T>.HasValue property is false.
//
// Returns:
// The value of the System.Nullable<T>.Value property if the System.Nullable<T>.HasValue
// property is true; otherwise, the defaultValue parameter.
public T GetValueOrDefault(T defaultValue);
//
// Summary:
// Returns the text representation of the value of the current System.Nullable<T>
// object.
//
// Returns:
// The text representation of the value of the current System.Nullable<T> object
// if the System.Nullable<T>.HasValue property is true, or an empty string ("")
// if the System.Nullable<T>.HasValue property is false.
public override string ToString();
}
该结构提供了一系列对T进行操作的方法,属性。 上述代码我们也可以这样写: static void Main(string[] args)
{
Nullable<int> sum = Sum(23, null);
} public static Int32? Sum(Int32? value, Int32? value1)
{
return value + value1;
}
也就是说我们在用int?的时候,编译器实际会把它编译成:Nullable<int>结构,然后对该结构进行操作,该结构重载了对操作符的操作。 装箱和拆箱: int? a = 3;
object o = a; 这段代码会导致a进行装箱。 在装箱的过程中,如果a的Value为null,则将null赋给o,此时不会进行装箱操作,如果a的值不是null,则会对int类型的a进行装箱,并将引用赋给o. int? b = (int?)o; 在拆箱过程中,如果o指向的引用值为null,则将b和Value赋为null,此时不会发生拆箱操作,如果o指向的引用值不为null,则将o引用的值通过拆箱操作赋给b. 空接合操作符: 有时我们在给一个变量赋值的时候会这样写: int? a = 2;
int? b = a != null ? a : 1; 现在有一种更简单的写法: int? a = 2;
int? b = a ?? 1;