int? num = 10; 定义了一个 可空值类型(Nullable Value Type) 的变量 num,并给它赋值为 10。核心是解决「普通值类型(如 int)不能存储 null」的问题,让 int 类型既可以存具体数值(如 10),也可以存「无值」状态(null)。

一、先拆解语法:int? 是什么?

int? 是 C# 的 语法糖(简化写法),本质等价于 Nullable<int>——Nullable<T> 是 .NET 提供的泛型结构(T 必须是「值类型」,如 intdoublebool 等),专门用于给值类型增加「存 null」的能力。

所以这行代码完全等价于:

Nullable<int> num = 10;
  • int:基础值类型(默认不能存 null,默认值是 0);
  • ?:C# 提供的简写符号,告诉编译器 “这个 int 允许存 null”;
  • num = 10:给可空 int 赋值为具体数值 10(此时 num 处于「有值」状态)。

二、核心作用:为什么需要 int??(解决了什么问题?)

普通 int 有个局限:必须有值(默认是 0),无法表示「无值」的场景。而实际开发中,“无值” 是很常见的需求,比如:

  1. 数据库中的字段(如 “年龄”)可能未填写,对应 NULL
  2. 表单输入的可选值(如 “身高”),用户可能没输入;
  3. 方法的可选返回值(如查询数据未找到,返回 “无结果” 而非默认 0)。

举个对比示例:

// 普通 int:不能存 null,默认值是 0
int normalInt; // 未赋值,编译警告(需初始化),默认值 0
normalInt = null; // 编译错误!普通值类型不能赋值为 null

// 可空 int:可以存 null,默认值是 null
int? nullableInt; // 未赋值,默认值是 null(无编译警告)
nullableInt = 10; // 合法:存具体数值
nullableInt = null; // 合法:存“无值”状态

三、int? 的关键用法(如何操作 num?)

由于 int? 可能是「有值」或「无值」,操作时需要先判断状态,避免报错。核心用法分 3 类:

1. 判断是否有值(避免 NullReferenceException

用 HasValue 属性(bool 类型)判断:

  • num.HasValue == truenum 有值(如 10);
  • num.HasValue == falsenum 无值(null)。

也可以用 is not null(C# 7.0+ 推荐,更简洁):

int? num = 10;

// 方式1:HasValue 判断(传统写法)
if (num.HasValue)
{
    Console.WriteLine("num 有值:" + num.Value); // 输出:num 有值:10
}
else
{
    Console.WriteLine("num 无值");
}

// 方式2:is not null 判断(现代写法,和你之前问的空值判断一致)
if (num is not null)
{
    Console.WriteLine("num 有值:" + num); // 有值时可直接输出,编译器自动解包
}

2. 获取具体值(2 种安全方式)

  • 方式 1:Value 属性(仅当 HasValue == true 时可用,否则抛异常);
  • 方式 2:?? 空合并运算符(无值时返回默认值,更安全)。

示例:

int? num1 = 10;
int? num2 = null;

// 方式1:Value 属性(有值时使用)
int val1 = num1.Value; // 正确:val1 = 10
// int val2 = num2.Value; // 运行时异常!num2 是 null,不能用 Value

// 方式2:?? 空合并运算符(无值时返回默认值)
int val3 = num1 ?? -1; // num1 有值,返回 10 → val3 = 10
int val4 = num2 ?? -1; // num2 无值,返回默认值 -1 → val4 = -1

// 简化场景:给无值的 num 赋值默认值
num2 ??= 0; // 等价于:if (num2 == null) num2 = 0; 现在 num2 = 0

3. 与普通 int 的转换

  • 可空 int → 普通 int:必须显式转换(或用 ?? 给默认值),避免无值时出错;
  • 普通 int → 可空 int:隐式转换(直接赋值即可)。

示例:

int normalInt = 20;
int? nullableInt;

// 普通 int → 可空 int:隐式转换(直接赋值)
nullableInt = normalInt; // 合法:nullableInt = 20

// 可空 int → 普通 int:显式转换(需确保有值)
if (nullableInt.HasValue)
{
    normalInt = (int)nullableInt; // 合法:强制转换(有值时安全)
}

// 或用 ?? 给默认值(推荐,避免判断)
normalInt = nullableInt ?? 0; // 有值取原值,无值取 0

四、int? 的默认值与注意事项

1. 默认值

  • 未赋值的 int? 默认是 null(而非普通 int 的 0):
    int? num; // 默认值 null
    Console.WriteLine(num == null); // 输出:True
    

2. 常见误区

  • 误区 1:直接用 num.Value 而不判断是否有值 → 运行时抛 InvalidOperationException
  • 误区 2:认为 int? 是引用类型 → 错!int? 本质是 Nullable<T> 结构(值类型),存储在栈上,只是多了一个 “是否有值” 的标记;
  • 误区 3:num == 10 会报错 → 错!可空值类型支持直接与基础类型比较(编译器自动处理):
    int? num = 10;
    Console.WriteLine(num == 10); // 输出:True(正确)
    Console.WriteLine(num == 20); // 输出:False(正确)
    

五、实际应用场景示例(贴近开发)

场景 1:数据库查询(年龄字段可能为 NULL)

// 模拟数据库查询:可能返回年龄(有值)或未填写(null)
int? GetUserAge(int userId)
{
    if (userId == 1) return 25; // 有值
    if (userId == 2) return null; // 无值(未填写)
    return null;
}

// 使用
int? userAge = GetUserAge(2);
string ageText = userAge switch
{
    not null => $"年龄:{userAge} 岁",
    null => "年龄:未填写"
};
Console.WriteLine(ageText); // 输出:年龄:未填写

场景 2:表单输入验证(可选数值)

// 模拟表单输入:用户可能输入身高,也可能不输入
string input = Console.ReadLine();
int? height = null;
if (!string.IsNullOrEmpty(input) && int.TryParse(input, out int h))
{
    height = h; // 输入有效,赋值给可空 int
}

// 显示结果
Console.WriteLine(height.HasValue ? $"身高:{height}cm" : "身高:未输入");

六、总结

int? num = 10; 的核心是:

  1. 定义一个「允许存 null」的整数变量 num,当前值为 10
  2. 解决普通 int 无法表示「无值」的问题,适配数据库、表单等实际场景;
  3. 操作时需先判断是否有值(HasValue 或 is not null),用 Value 或 ?? 安全取值;
  4. int? 是值类型(Nullable<int>),不是引用类型,性能与普通 int 接近。

简单记:int? = int + 允许 null,是处理 “可选数值” 的必备语法。

 

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐