C#:类型定义中使用‌问号(?)

在 C# 中,类型定义中的‌**问号(?)**‌主要用于控制类型的可空性,但具体行为因类型(值类型或引用类型)和 C# 版本而异。以下是清晰分类的说明:


一、可空值类型(T?,适用于所有 C# 版本)

‌用途 ‌:允许值类型(如 int、DateTime 等)存储 null 值。

‌语法 ‌:在值类型后加 ?,底层由 System.Nullable<T> 结构实现。

‌示例‌:

int? age = null; // 声明可空整型 DateTime? date = null; // 声明可空日期

‌核心操作‌:

  • ‌判空 ‌:通过 HasValue 属性检查是否有值。

    if (age.HasValue) Console.WriteLine(age.Value);

  • ‌安全取值 ‌:使用 ?? 提供默认值,避免 InvalidOperationException。

    int safeAge = age ?? 0; // 若 age 为 null,返回 0

  • ‌强制转换 ‌:直接将 int? 赋值给 int 会报错,需显式转换。

    int value = (int)age; // 若 age 为 null,抛出异常

‌适用场景‌:

  • 数据库字段可能为 null(如 int? 对应 SQL 中的 NULL 整数字段)。
  • 需要区分"未赋值"和"有效值"(例如 0 和 null 语义不同)。

二、可空引用类型(T?,C# 8.0+)

‌用途 ‌:在严格模式下显式标记引用类型可为 null,避免空引用异常。

‌语法 ‌:在引用类型后加 ?(需启用 #nullable enable)。

‌示例‌:

#nullable enable string? name = null; // 显式声明可为 null 的字符串 string title = null; // 严格模式下会警告:需改为 string?

‌核心规则‌:

  • ‌严格模式 ‌:启用后,引用类型默认不可为 null,需显式用 ? 标记。

    #nullable enable public string? GetComment() { ... } // 可能返回 null

  • ‌安全访问 ‌:使用 ?. 和 ?? 避免运行时异常。

    int length = name?.Length ?? 0; // 安全访问属性

‌适用场景‌:

  • API 设计:明确参数或返回值是否可为 null。

    public void SaveData(string id, string? optionalNote = null) { ... }

  • 反序列化 JSON 数据:处理可能缺失的字段。 public class User { public string Name { get; set; } // 必须存在 public string? Email { get; set; } // 允许为 null }


三、关键区别与注意事项

‌特性‌ 可空值类型(int?) 可空引用类型(string?)
‌适用类型‌ 值类型(struct) 引用类型(class)
‌底层实现‌ System.Nullable<T> 结构 编译时静态分析,无运行时类型变化
‌默认可空性‌ 必须用 ? 声明才可为 null 严格模式下默认不可为 null
‌运行时表现‌ 实际存储为 T 或 null 编译警告,但运行时仍可能为 null

四、常见问题与解决

  1. ‌**错误:不可空类型接收 null**‌

    string name = null; // 严格模式下警告

    ‌修复‌:

    string? name = null; // 显式标记可空

  2. ‌错误:未处理可空值类型‌

    int? age = null; int value = age; // 编译错误

    ‌修复‌:

    int value = age ?? 0; // 提供默认值

  3. ‌安全调用链‌

    var length = user.Address?.City?.Length; // 避免多层 null 检查


五、最佳实践

  1. ‌启用严格模式 ‌:在 .csproj 中配置 <Nullable>enable</Nullable>,提升代码安全性。
  2. ‌明确可空性 ‌:公共 API 的参数和返回值显式标记 ?。
  3. ‌防御性编程 ‌:对可空类型进行判空(if (x != null))或使用 ??、?. 运算符。

通过合理使用 ?,可以显著减少空引用异常,提升代码健壮性,尤其在处理外部数据(如数据库、API 响应)时至关重要。

相关推荐
CSharp精选营3 小时前
我用 ASP.NET Core 做了个水稻病虫害检查系统
c#·毕业设计·.net core·码农刚子
唐青枫3 小时前
我用 C# 开发了一款电子发票自动整理工具
c#·.net
下页、再停留3 小时前
【C#桌面客户端系列学习-2】在原来窗口基础上打开新窗口
c#·visual studio
Behavior3 小时前
Unity 手游 iOS Deep Link 唤醒全流程:从 URL Scheme / Universal Links 到 C# 层参数投递
c#·unity3d·游戏开发
我是唐青枫3 小时前
我用 C# 开发了一款电子发票自动整理工具
c#·.net
WAKU3 小时前
C#: 爸爸再爱我一回! 写在微软使用Rust重写GitHub Copilot之后的碎碎念
microsoft·rust·微软·c#·编程语言
唐青枫3 小时前
别把 WPF 写成一个 MainWindow:C#.NET Prism 模块化开发详解
c#·.net
用户788477316343 小时前
WPF 数据绑定 5 个隐形坑:第 3 个 90% 的人都栽过
c#
小羊没烦恼!6 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
神仙别闹6 天前
基于C#+MySQL实现(WinForm)个人聊天室软件
c#