在.NET中,可空类型是如何实现的?

16 浏览
0 Comments

在.NET中,可空类型是如何实现的?

在我们自己的Jon Skeet的《C#深入研究》一书中,他讨论了模拟值类型的“null”的3种方法:\n

    \n

  • 魔术值(例如,最早可能的DateTime被视为“null”)
  • \n

  • 引用类型包装器
  • \n

  • 布尔标志
  • \n

\n提到可空类型使用第三种方法。可空类型在底层是如何工作的?

0
0 Comments

在.NET中,可空类型是如何实现的?这个问题的出现是因为在C#中,结构体(struct)不能直接赋值为null,而可空类型(Nullable)又是通过结构体来实现的。

为了解决这个问题,可空类型在内部提供了两个字段:hasValue和value。当我们将可空类型赋值为null时,hasValue被设置为false。而当我们将可空类型赋值为非null值时,hasValue被设置为true,并且value字段存储了实际的值。

这样一来,通过判断hasValue字段的值,我们就可以知道可空类型是否为null,如果为null可以执行相应的逻辑处理。而如果不为null,我们可以通过访问value字段来获取实际的值。

这种实现方式使得我们可以在结构体中模拟出引用类型的null值,从而在使用结构体时更加灵活。同时,这种实现方式也符合了C#中结构体不能直接赋值为null的限制。

0
0 Comments

在.NET中,可空类型是如何在底层实现的?这个问题的出现的原因是人们想了解可空类型的实现细节及其特殊之处。下面是可空类型在.NET中的实现方式以及解决方法的整理:

可空类型实际上是一个带有bool标志的通用结构体,除了具有特殊的装箱规则。因为结构体默认情况下被初始化为零,所以bool默认为false(没有值):

public struct Nullable where T : struct {
    private readonly T value;
    private readonly bool hasValue;
    public Nullable(T value) {
        this.value = value;
        hasValue = true;
    }
    public T Value {
        get {
           if(!hasValue) throw some exception ;-p
           return value;
        }
    }
    public T GetValueOrDefault() { return value; }
    public bool HasValue {get {return hasValue;}}
    public static explicit operator T(Nullable value) {
        return value.Value; }
    public static implicit operator Nullable(T value) {
        return new Nullable(value); }
}

此外,还有一些特殊之处:

- 特殊的装箱规则(通常情况下无法实现)

- C#中与null比较等特殊规则

- C#中的“lifted”运算符(以及.NET中的EqualityComparer、Comparer等)

- 泛型类型约束的特殊规则(防止Nullable>的出现)

装箱是如何处理的?我能为自己的结构体实现自定义的装箱规则吗?

装箱是由CLI中的特殊规则处理的。不,你不能自己实现这个。类似地,“lifted”运算符也不是你可以自己实现的。

值得注意的是,操作符的行为受语言规范的控制-C#和VB在各种操作符上有不同的规则。

我刚遇到了一个区别:你可以给T?方法参数设置默认值为T,但是如果你实现自己的可空类型并尝试做同样的事情,会得到一个编译错误(例如,“bool类型的值不能作为默认参数使用,因为没有到MyNullable类型的标准转换。”)。这是否属于你提到的某个问题?

这个问题属于可空类型的特殊规则之一。

0