提问人:Maxim Gershkovich 提问时间:8/3/2012 更新时间:8/4/2012 访问量:2313
引用类型与可为 Null 的类型 ToString()
Reference types vs Nullable types ToString()
问:
有人可以解释为什么调用空引用类型会导致异常(在我看来这是完全有道理的,你不能调用一个方法!)但是调用一个空的返回?这让我感到非常惊讶,因为我认为不同类型的行为是一致的。ToString()
ToString()
Nullable(Of T)
String.Empty
Nullable<Guid> value = null;
Stock stock = null;
string result = value.ToString(); //Returns empty string
string result1 = stock.ToString(); //Causes a NullReferenceException
答:
Nullable 是一种值类型,赋值会导致它使用 和 进行初始化。null
Value=null
HasValue=false
此外,Nullable.ToString() 的实现方式如下:
public override string ToString()
{
if (!this.HasValue)
{
return "";
}
return this.value.ToString();
}
所以你所看到的是意料之中的。
评论
对于可为 null 的类型,这有点棘手。当你把它设置为它时,它实际上不是因为它不是引用类型(它是值类型)。当你用它初始化这样的变量时,它会创建一个新的结构实例,其中 property is 和 it's is ,所以当你调用方法时,它在结构实例上工作得很好。null
null
null
HasValue
false
Value
null
ToString
评论
null
null
null
42.0
double
double? d = null;
d
double == null
true
null
d
null
如果调查定义,则会重写 ToString 定义。在此函数中,重写 ToString 以返回 String.Empty。Nullable<>
// 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();
另一方面,Stock 是一个自定义类,我假设 ToString 没有被覆盖。因此,它返回 NullReferenceException,因为它使用默认行为。
评论
ToString()
Stock
Stock
Stock
Nullable<Guid>
Nullable<>
ToString()
Nullable<T>
实际上是一个具有一些编译器支持和实现支持的行为,但实际上却没有。struct
null
null
您看到的是实现之间的冲突,允许您像对待任何其他引用类型一样自然地将其视为方法调用,但允许方法调用发生,因为 实际上不是 null,它里面的值是 null。null
Nullable<T>
从视觉上看,它似乎不应该起作用,这仅仅是因为您看不到在后台为您完成的工作。
当您对 null 引用类型调用扩展方法时,可以看到其他此类视觉技巧......该调用有效(与视觉预期相反),因为在后台,它被解析为静态方法调用,将 null 实例作为参数传递。
评论
class A{public void DoNothing(){}};/*...*/(A(null)).DoNothing();
DoSomething
Nullable<bool> b = null;
根据 MSDN 备注
Guid.ToSTring() 方法 返回 此 Guid 实例的值,根据提供的格式 规范。
根据 MSDN 对 Nullable 的备注
如果一个类型可以被赋值,或者可以 赋值 null,这意味着该类型没有任何值。 因此,可为 null 的类型可以表示一个值,也可以表示没有值 存在。例如,引用类型(如 String)可为 null, 而 Int32 等值类型则不是。值类型不能是 可为 null,因为它有足够的容量仅表示值 适合该类型;它没有额外的容量 需要表示值 null。
评论
调用引发的异常是有原因的,它正在调用对 null 引用的方法。 另一方面,不是 null 引用,因为它不是引用;它是一种值类型,其值等效于 null。default(object).ToString()
NullReferenceException
default(int?)
最大的实际要点是,如果这样做,那么以下操作将失败:
default(int?).HasValue // should return false, or throw an exception?
它还会搞砸我们混合 null 和 non-nullable 的能力:
((int?)null).Equals(1) // should return false, or throw an exception?
以下内容变得完全无用:
default(int?).GetValueOrDefault(-1);
我们可以摆脱并强制与 null 进行比较,但是如果在某些情况下与 null 相比,使 null 的值类型的等式覆盖可以返回 true,该怎么办?这可能不是一个好主意,但它是可以做到的,语言必须应对。HasValue
让我们回想一下为什么引入可为 null 的类型。引用类型可以为 null 的可能性是引用类型概念中固有的,除非努力强制执行非 null 性:引用类型是引用某物的类型,这意味着不引用任何事物的可能性,我们称之为 null。
虽然在许多情况下很麻烦,但我们可以在各种情况下使用它,例如表示“未知值”、“无有效值”等(例如,我们可以将其用于数据库中的 null 含义)。
在这一点上,我们已经在给定的上下文中赋予了 null 一个含义,而不仅仅是给定引用不引用任何对象的简单事实。
由于这很有用,因此我们可以想要将 or 设置为 null,但我们不能,因为它们不是引用其他事物的类型,因此不能处于不引用任何事物的状态,就像我作为哺乳动物可以失去羽毛一样。int
DateTime
2.0 中引入的可为 null 类型为我们提供了一种值类型形式,该值类型可以通过与引用类型不同的机制具有语义 null。如果它不存在,你可以自己编写大部分代码,但特殊的装箱和推广规则允许更明智的装箱和操作员使用。
好。现在让我们首先考虑一下为什么会发生这种情况。其中两个是不可避免的,一个是 C# 中的设计决策(不适用于所有 .NET)。NullReferenceExceptions
- 您尝试调用虚拟方法或属性,或访问空引用上的字段。这必须失败,因为没有办法查找应该调用什么覆盖,也没有这样的字段。
- 对 null 引用调用非虚拟方法或属性,而 null 引用又调用虚拟方法或属性,或访问字段。这显然是第一点的一个变体,但我们接下来要讨论的设计决策的优点是保证这在一开始就失败,而不是中途失败(这可能会令人困惑并产生长期副作用)。
- 对空引用调用非虚拟方法或属性,该引用不调用虚拟方法或属性,也不访问字段。没有内在的理由不应该允许这样做,有些语言允许这样做,但在 C# 中,为了一致性,他们决定使用而不是强制使用(不能说我同意,但你去吧)。
callvirt
call
NullReferenceException
这些情况都不适用于可为 null 的值类型。不可能将可为 null 的值类型放入无法知道要访问的字段或方法重写的条件中。“只是”的整个概念在这里没有意义。NullReferenceException
总而言之,不抛出 a 与其他类型一致 - 当且仅当使用 null 引用时,通过它进行类型。NullReferenceException
请注意,有一种情况是调用 null 可为 null 类型会抛出,它使用 ,因为不是虚拟的,并且当调用值类型时,总是有一个隐含的装箱。其他值类型也是如此,因此:GetType()
GetType()
(1).GetType()
被视为:
((object)1).GetType()
但是在可为 null 的类型的情况下,装箱会将带有 false 的类型转换为 null,因此:HasValue
default(int?).GetType()
被视为:
((object)default(int?)).GetType()
这会导致对 null 对象进行调用,从而引发。GetType()
顺便说一句,这让我们明白了为什么不假装是更明智的设计决策——需要这种行为的人总是可以装箱的。如果您希望它通过,请使用,这样语言就无需将其视为强制异常的特例。NullReferenceType
((object)myNullableValue).GetString()
编辑
哦,我忘了提到背后的机制.NullReferenceException
测试非常便宜,因为它大多只是忽略问题,然后在发生异常时从操作系统中捕获异常。换句话说,没有测试。NullReferenceException
请参阅引发/生成 null 引用异常背后的 CLR 实现是什么?,并注意这些都不适用于可为 null 的值类型。
评论
String
评论