Csharp 中的可空类型及其使用

发布日期:2026-07-14 02:23:03   来源 : 杭州电子商务研究院    浏览量 :12
杭州电子商务研究院 发布日期:2026-07-14 02:23:03  
12

介绍

可空类型是在 C# 7.0 版中引入的。这些类型表示System.Nullable<T>类的实例。它们是基础类型T的值和附加的值。T可以是任何非可空值类型,但不能是引用类型。本指南将向您介绍这个相对较新的功能,并向您展示它旨在解决哪些类型的问题。我们将看到实际示例,展示这个新功能如何在大多数与空值相关的错误导致应用程序崩溃之前修复它们。

十亿美元的错误

1965 年,计算机科学界的巨人之一托尼·霍尔 (Tony Hoare)发明了空引用。当时,他正在设计面向对象语言 ALGOLW 中的第一个引用类型系统。他的目标是确保所有引用的使用都是绝对安全的,而编译器的检查可以确保这一点。他把空引用放在这里,原因很简单:它很容易实现。这导致了无数的错误、漏洞和系统崩溃。据估计,在过去五十年左右的时间里,它造成了数十亿美元的损失。

这就是为什么空引用被称为“十亿美元的错误”。

可空类型

问题在于使用空引用是多么容易。这些是 C# 中每个引用类型的默认值。这个问题的答案是:

  • 默认值还能是什么?
  • 在您决定之前,哪个其他值最合适? - 在用实际值填充之前,可以使用哪个其他值来初始化数组或引用?

问题(或至少部分问题)来自于这样一个事实:C# 不允许您表达在特定上下文中将 null 作为值是好还是坏。

您能做什么?

  1. 表达意图
  2. 强制行为
  3. 避免取消引用空值
  4. 避免空值

当我们需要表示基础类型的未定义值时,我们会使用可空类型。虽然布尔值可以有truefalse值,但在这种情况下,null 表示false,因为没有未定义的值。当您进行数据库交互时,变量值可以是未定义的或缺失的。数据库中的字段可能包含truefalse或根本没有值。在这种情况下, bool类型的可空值是可行的方法。

使用可空类型时需要记住以下几点:

  1. 此类型表示可以分配空值的值类型变量。
  2. T ?是Nullable< T >的简写语法
  3. 像对其他类型进行操作一样为可空类型分配一个值int? = nulldouble? = 10.0
  4. HasValueValue只读属性可用于检查并获取此类类型的值。
  5. ==!=运算符可与可空类型一起使用。
  6. 从 C# 7.0 版本开始,您可以使用模式匹配。
  7. T?的默认值是HasValue计算结果为 false 的实例
  8. ??运算符(空合并运算符)允许您根据可空类型的值为基础类型分配一个值。

让我们声明一些可空类型。

      using System;

namespace nllables
{   
    class Program
    {
        static void Main(string[] args)
            {
            double? nullableDouble = 9.99;
            int? nullableInt = null;
            double standardDouble = 19.19;
            Console.WriteLine($"The variable :: {nameof(nullableDouble)} has value :: {nullableDouble} and HasValue evaluates to :: {nullableDouble.HasValue}.");
            if(nullableInt.HasValue)
                { Console.WriteLine($"The variable :: {nameof(nullableInt)} has value :: {nullableInt.Value} and HasValue evaluates to :: {nullableInt.HasValue}"); }
            else
                { Console.WriteLine($"The variable :: {nameof(nullableInt)} has no value!"); }
            Console.WriteLine($"The variable :: {nameof(standardDouble)} has value :: {standardDouble}.");
            Console.ReadKey();
            }
    }
}
    

这给了我们以下输出:

      The variable :: nullableDouble has value :: 9.99 and HasValue evaluates to :: True.
The variable :: nullableInt has no value!
The variable :: standardDouble has value :: 19.19.
    

在这个演示中,我们将使用简写语法来声明两个可空类型,一个是 double,一个是int。我们if块中使用HasValue来决定int的值是否正确。

如果我们尝试在没有if块的情况下引用int,我们会看到以下异常:

      System.InvalidOperationException: 'Nullable object must have a value.'
    

此异常在编译时弹出。让我们在投入生产之前修复此问题。

我们将可空类型转换为基础类型。

      using System;

namespace nllables
{   
    class Program
    {
        static void Main(string[] args)
            {
            double? d = null;
            int? c = 9;

            int g = c ?? 99;
            double f = d ?? 99.9;

            Console.WriteLine("The nullables...");
            if (d.HasValue)
                { Console.WriteLine($"The variable: {nameof(d)} has value of {d.Value}"); }
            else
                { Console.WriteLine($"The variable: {nameof(d)} has is null!"); }

            if (c.HasValue)
            { Console.WriteLine($"The variable: {nameof(c)} has value of {c.Value}"); }
            else
            { Console.WriteLine($"The variable: {nameof(c)} has is null!"); }

            Console.WriteLine("The converted...");
            Console.WriteLine($"The variable: {nameof(g)} has value of {g}");
            Console.WriteLine($"The variable: {nameof(f)} has value of {f}");

            Console.ReadKey();
            }
    }
}
    

输出如下:

      The nullables...
The variable: d has is null!
The variable: c has value of 9
The converted...
The variable: g has value of 9
The variable: f has value of 99.9
    

我们有两个可空类型变量,dc。空合并运算符允许我们将变量的值转换为标准变量类型gf

我们的转换可能需要一些解释。int g = c ?? 99;这行代码在后台工作,如下所示。它检查 c 是否可空类型,并调用HasValue运算符,如果返回值为true,则将其分配给g;否则分配 99**。同样的事情发生在double f = d ?? 99.9;中,它显示了另一种情况,其中变量的值为null ,因此将99.9分配给f` 变量。请记住,就值而言,这些值需要隐式转换。

举个简单的例子,下面的操作将会因为异常而终止:

      int g = c ?? 99.9;
    

错误指出:

      CS0266	Cannot implicitly convert type 'double' to 'int'.
An explicit conversion exists (are you missing a cast?)
    

那么运营商又如何呢?

      using System;

namespace nllables
{   
    class Program
    {
        static void Main(string[] args)
            {
            double? a = null;
            double? b = 99.9;

            bool? c = true;
            bool? d = false;
            bool? e = null;

            int? f = 10;
            int? g = null;

            Console.WriteLine("Do the math...");
            Console.WriteLine($"a + b = {(a + b)}");
            Console.WriteLine($"a * b = {a * b}");
            Console.WriteLine($"a * f = {a * f}");
            Console.WriteLine($"b * f = {b * f}");
            Console.WriteLine("The booleans...");
            Console.WriteLine($"c | d = {c | d}");
            Console.WriteLine($"c | e = {c | e}");
            Console.WriteLine($"d & e = {d & e}");
            Console.WriteLine($"c & e = {c | e}");

            Console.ReadKey();
            }
    }
}
    

结果:

      c | d = True
c | e = True
d & e = False
c & e = True
    

从这个实验中,我们得出结论,数学领域的任何运算,当涉及两边的零值时,都不会产生任何结果。至于布尔部分,情况有点复杂,因为c & e = True表示true & null结果是True,而false & null计算结果为False。如果您有兴趣,本文将进一步讨论可空布尔逻辑运算符

结论

以上内容来自杭州电子商务研究院推送
关注
关于我们
热门推荐
合作伙伴
免责声明:本站部分资讯来源于网络,如有侵权请及时联系客服,我们将尽快处理
Copyright © 2025-2027 ToB产业网址导航 公安备案 浙公网安备33010602013138号 浙ICP备16025413号-9
支持 反馈 关注 数据