int? 与int
int?num = 10;定义一个「允许存 null」的整数变量num,当前值为10;解决普通int无法表示「无值」的问题,适配数据库、表单等实际场景;操作时需先判断是否有值(HasValue或),用Value或??安全取值;int?是值类型(),不是引用类型,性能与普通int接近。int?int+ 允许null,是处理 “可选数值” 的必备语法。
int? num = 10; 定义了一个 可空值类型(Nullable Value Type) 的变量 num,并给它赋值为 10。核心是解决「普通值类型(如 int)不能存储 null」的问题,让 int 类型既可以存具体数值(如 10),也可以存「无值」状态(null)。
一、先拆解语法:int? 是什么?
int? 是 C# 的 语法糖(简化写法),本质等价于 Nullable<int>——Nullable<T> 是 .NET 提供的泛型结构(T 必须是「值类型」,如 int、double、bool 等),专门用于给值类型增加「存 null」的能力。
所以这行代码完全等价于:
Nullable<int> num = 10;
int:基础值类型(默认不能存null,默认值是0);?:C# 提供的简写符号,告诉编译器 “这个int允许存null”;num = 10:给可空int赋值为具体数值10(此时num处于「有值」状态)。
二、核心作用:为什么需要 int??(解决了什么问题?)
普通 int 有个局限:必须有值(默认是 0),无法表示「无值」的场景。而实际开发中,“无值” 是很常见的需求,比如:
- 数据库中的字段(如 “年龄”)可能未填写,对应
NULL; - 表单输入的可选值(如 “身高”),用户可能没输入;
- 方法的可选返回值(如查询数据未找到,返回 “无结果” 而非默认
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 == true:num有值(如10);num.HasValue == false:num无值(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; 的核心是:
- 定义一个「允许存 null」的整数变量
num,当前值为10; - 解决普通
int无法表示「无值」的问题,适配数据库、表单等实际场景; - 操作时需先判断是否有值(
HasValue或is not null),用Value或??安全取值; int?是值类型(Nullable<int>),不是引用类型,性能与普通int接近。
简单记:int? = int + 允许 null,是处理 “可选数值” 的必备语法。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)