4

我想知道是否有人知道 C# 编译器如何处理以下分配:

int? myInt = null;

我的假设是执行了隐式转换,但我无法弄清楚如何处理空文字赋值。我反汇编了 System.Nullable 对象,发现隐式运算符被覆盖为:

public static implicit operator T?(T value)  {
    return new T?(value);  
}

一旦被调用,它将尝试触发辅助构造函数:

public Nullable(T value) {
    this.value = value;
    this.hasValue = true; 
}

这就是我的困惑发挥作用的地方...... this.value 是某种值类型,不能为空。

那么,有谁知道这种“魔术”是如何发生的......或者我假设调用了辅助构造函数是错误的?是否调用了默认构造函数,因为编译器知道它无法将第二个构造函数的签名与 null 文字匹配(导致 myInt 被分配给新的“null”Nullable)?

4

5 回答 5

8

该声明:

int? myInt = null;

编译为:

  .locals init (valuetype [mscorlib]System.Nullable`1<int32> V_0)
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    valuetype [mscorlib]System.Nullable`1<int32>

根据 MSDN ,这意味着«将指定地址处的值类型的每个字段初始化为空引用或适当原始类型的 0。»

所以这里没有构造函数或转换。HasValue 将返回 false,并且尝试获取其 Value 将引发 InvalidOperationException。当然,除非您使用 GetValueOrDefault。

于 2009-04-02T21:21:44.963 回答
3

真正发生的是,当您分配null给可空类型实例时,编译器只需使用默认构造函数( Jb answerT?上的 initobj IL 指令)创建 的新实例,因此以下两行是等效的:

int? a = null;
Nullable<int> b = new Nullable<int>();

object.Equals(a,b); // true

因此你不能这样做:

Nullable<int> c = new Nullable<int>(null);

类似的事情发生然后你将一个可为空的类型与 null 进行比较:

if (a == null)
{
  // ...
}

在幕后,它只是调用 a.HasValue 属性。

于 2009-04-02T21:59:36.527 回答
0

我希望.HasValue设置为false.Value设置为default(T),但我没有检查过。

于 2009-04-02T21:17:33.493 回答
0

就像是:

public Nullable() {
    this.value = default(T);
    this.hasValue = false;
}
于 2009-04-02T21:18:35.957 回答
-2

C# 是一种高级语言,可以编译为 IL

随着可空类型的引入,C# 标准发生了变化,因此 C# 编译器的行为必须改变以处理新规则,例如“除了 Nullable 之外,没有任何结构可以分配 null 值”。

通常不允许将 null 分配给结构,但这只是编译器在生成 IL 时强制执行的规则。由于编译器会解析你的所有代码并弄清楚它的含义,它可以识别各种规则,即使是在你看来可能是例外的规则。

基本上,如果编译器解析您的 C# 代码并发现您将 null 分配给结构,它会输出错误。如果它发现您将 null 分配给一个Nullable<T>结构,那么它知道如何处理它并生成适当的 IL。

从 C# 标准:

13.7.1空类型转换:“存在从空类型(第 11.2.7 节)到任何可空类型的隐式转换。此转换产生给定可空类型的空值(第 12.2 节)。”

12.2默认值:“可空类型的默认值是 HasValue 属性为 false 的实例。引用可空类型的默认值的 Value 属性会导致 System.InvalidOperationException 类型的异常。默认值也是称为可空类型的空值。存在从空类型(第 11.2.7 节)到任何可空类型的隐式转换,并且此转换产生该类型的空值。

于 2009-04-19T19:12:23.793 回答