【.NET Core】可为null类型详解

简介: 【.NET Core】可为null类型详解


一、概述

null关键字是表示不引用任何对象的空引用的文字值。null是引用类型变量的默认值。普通值类型不能为null,可为空的值类型除外


二、可为空的值类型

可为null值类型T?表示其基础值类型T的所有值及额外的null值。基础值类型T本身不能是可为空的值类型。


任何可为空的值类型都是泛型System.Nullable<T>结构的实例。可使用以下任何一种互换形式引用具有基础类型T的可为空值类型:Nullable<T>或T?。


需要表示基础类型的未定义值时,通常使用可为空的值类型。如:布尔值或bool变量只能为true或false。但是,在某些应用程序中,变量值可能未定义或缺失。在这种情况下可以使用bool?类型。

2.1 声明和赋值

由于值类型可隐式转换为相应的可为空的值类型,因此可以像其基础类型赋值一样,向可为空值类型的变量赋值,还可以分配null值。具体实例如下:

double? pi=3.1415926;
char? letter='c';
int a=110;
int? ab=a;
bool? flag =null;
int?[] arr= new int?[8];

可为空值类型的默认值表示null,也就是说,它是其Nullable<T>.HasValue属性返回false的实例。

2.2 检查可为空值类型

可将is运算符与类型模式结合使用,既检查null的可为空值类型的实例,又检索基础类型的值:

int? a = 42;
if(a is int valueOfA){
   Console.WriteLine($"a is {valueOfA}");  
}else{
   Console.WriteLine("a does not have a value.");   
}

始终可以使用以下只读属性来检查和获取可为空值类型变量的值:


  • Nullable<T>.HasValue指示可为空值类型的实例是否有基础类型的值。
  • 如果HasValue为true,则Nullable<T>.Value获取基础类型的值。如果HasValue为false,则Value属性将引发IvalidOperationException。

使用HasValue属性在显示值之前测试变量是否包含该值:

int? b=10;
if(b.HasValue)
{
    Console.WriteLine($"b is {b.Value}");
}else{
    Console.WirteLine("b does not have a value.");
}

还可以通过可为空类型与null进行比较,如:

int? bc = 7;
if (bc != null)
{
    Console.WriteLine($"c is {c.Value}");
}
else
{
    Console.WriteLine("c does not have a value");
}

2.3 基础类型与可为空的值类型互换

如果要将可为空值类型的值分配给不可以为null的值类型变量,则可能需要指定要分配的替代null的值。使用Null和并操作符??执行此操作(也可将Nullable<T>.GetValueOrDefault(T)方法用于相同的目的):

int? pi=3.14;
int b = pi??-1;
Console.WriteLine($"b is {b}");
int? c=null;
int d =c??-1;
Console.WriteLine($"d is {d}");

如果要使用基础值类型的默认值为null,需要使用Nullable<T>.GetValueOrDefault()方法。

还可以将可为空的值类型显示强制转换为不可为null的类型。如下:

int? n = null;
int n2 = (int)n;

在运行时,如果可为空的值类型的值为 null,则显式强制转换将抛出InvalidOperationException。不可为null的值类型T隐式转换为相应的可为空值类型T?


2.4 可为空的值类型装箱和取消装箱

可为空值类型的实例T?已装箱;

  • 如果HasValue返回false,则生成空引用。
  • 如果HasValue返回true,则基础值类型T的对应值将将装箱,而不对Nullable<T>的实例进行装箱。

可将值类型T的已装箱值取消装箱到相应的可为空值类型T?,如示例:


2.5 如何确定可为空的值类型

如果要确定实例是否是可为空的值类型,请不要使用Object.GetType方法获取要通过前面的代码测试的Type实例。如果对值类型可为空的实例调用Object.GetType方法,该实例将装箱到Object。由于对可为空的值类型的非NULL实例的装箱等同于对基础类型的值的装箱,因此GetType会返回表示可为空的值类型的基础类型的Type实例。


另外,请勿使用is运算符来确定实例是否是可为空的值类型。因为无法使用is运算符区分可为空值类型实例的类型与其基础类型实例。


综合来说,如果要判断可为空值类型,需要使用Nullable.GetUnderlyingType和typeof运算符。以检查实例是否具有可为空的值类型。


三、可为 null 的引用类型

由于可为null的感知上下文选择加入代码,可以使用可为null的引用类型。可为null的引用类型,null静态分析警告和null包容运算符是可选的语言功能。

在可为null的感知上下文中:


  • 引用类型T的变量必须用非null值进行初始化,并且不能为其分配可能为null的值。
  • 引用类型T?的变量可以用null进行初始化,也可以分配null,但是在取消引用之前必须对null进行验证检测。
  • 类型为T?的变量m在应用null包含运算符时被认为是非空的。

不可为null的引用类型T和可为null的引用类型T?之间的区别按照编译器对上述规则的解释强制执行的,类型为T的变量和类型为T?的变量由相同的.NET类型表示。

string notNull = "Hello";
string? nullable = default;
notNull = nullable!;
Console.WriteLine(notNull);

变量notNull和nullable都由String类型表示。因为不可为null的类型和可为null的类型都存储为相同的类型,所以有几个位置不允许使用可为null的引用类型。

下面几种情况不能使用可为nulll类型

  • 可为 null 的引用类型不能用作基类或实现的接口
  • 可为 null 的引用类型不能用于任何对象创建或类型测试表达式
  • 可为 null 的引用类型不能是成员访问表达式的类型
public MyClass : System.Object? // not allowed
{
}

var nullEmpty = System.String?.Empty; // Not allowed
var maybeObject = new object?(); // Not allowed
try
{
    if (thing is string? nullableString) // not allowed
        Console.WriteLine(nullableString);
} catch (Exception? e) // Not Allowed
{
    Console.WriteLine("error");
}
目录
相关文章
|
1月前
|
开发框架 缓存 .NET
并发请求太多,服务器崩溃了?试试使用 ASP.NET Core Web API 操作筛选器对请求进行限流
并发请求太多,服务器崩溃了?试试使用 ASP.NET Core Web API 操作筛选器对请求进行限流
117 0
|
21天前
|
开发框架 NoSQL .NET
利用分布式锁在ASP.NET Core中实现防抖
【9月更文挑战第5天】在 ASP.NET Core 中,可通过分布式锁实现防抖功能,仅处理连续相同请求中的首个请求,其余请求返回 204 No Content,直至锁释放。具体步骤包括:安装分布式锁库如 `StackExchange.Redis`;创建分布式锁服务接口及其实现;构建防抖中间件;并在 `Startup.cs` 中注册相关服务和中间件。这一机制有效避免了短时间内重复操作的问题。
|
1月前
|
开发框架 前端开发 中间件
聊聊 ASP.NET Core 中间件(二):中间件和筛选器的区别
聊聊 ASP.NET Core 中间件(二):中间件和筛选器的区别
|
1月前
|
开发框架 缓存 NoSQL
聊聊 ASP.NET Core 中间件(一):一个简单的中间件例子
聊聊 ASP.NET Core 中间件(一):一个简单的中间件例子
|
1月前
|
开发框架 .NET 数据库连接
闲话 Asp.Net Core 数据校验(三)EF Core 集成 FluentValidation 校验数据例子
闲话 Asp.Net Core 数据校验(三)EF Core 集成 FluentValidation 校验数据例子
|
1月前
|
开发框架 前端开发 .NET
闲话 ASP.NET Core 数据校验(二):FluentValidation 基本用法
闲话 ASP.NET Core 数据校验(二):FluentValidation 基本用法
|
1月前
|
开发框架 前端开发 .NET
闲话 ASP.NET Core 数据校验(一):内置数据校验
闲话 ASP.NET Core 数据校验(一):内置数据校验
|
1月前
|
存储 开发框架 算法
ASP.NET Core 标识(Identity)框架系列(四):闲聊 JWT 的缺点,和一些解决思路
ASP.NET Core 标识(Identity)框架系列(四):闲聊 JWT 的缺点,和一些解决思路
|
1月前
|
开发框架 JSON .NET
ASP.NET Core 标识(Identity)框架系列(三):在 ASP.NET Core Web API 项目中使用标识(Identity)框架进行身份验证
ASP.NET Core 标识(Identity)框架系列(三):在 ASP.NET Core Web API 项目中使用标识(Identity)框架进行身份验证
|
1月前
|
开发框架 监控 .NET
开发者的革新利器:ASP.NET Core实战指南,构建未来Web应用的高效之道
【8月更文挑战第28天】本文探讨了如何利用ASP.NET Core构建高效、可扩展的Web应用。ASP.NET Core是一个开源、跨平台的框架,具有依赖注入、配置管理等特性。文章详细介绍了项目结构规划、依赖注入配置、中间件使用及性能优化方法,并讨论了安全性、可扩展性以及容器化的重要性。通过这些技术要点,开发者能够快速构建出符合现代Web应用需求的应用程序。
33 0