返回题库高级 .NET 刷题C# 选择题 · 第 3 / 50 篇

C# 试题 03:可空类型与空值分析

0041 以下代码输出什么?

难度: 实战

int? a = null;
int? b = 5;

object o1 = a;
object o2 = b;

Console.WriteLine(o1 is null);   // 1
Console.WriteLine(o2 is int);    // 2
Console.WriteLine(o2 is int?);   // 3
  • A. 1、2 为 True,3 为 False
  • B. 全部为 True(无值的可空值类型装箱为 null;有值的装箱为底层值,is int? 匹配非空可空值)
  • C. 1 为 False,2 为 True
  • D. 3 编译失败
查看答案与解析

正确答案B

解析: 可空值类型装箱时:无值装箱为 null,有值装箱为底层值(int 而不是 Nullable<int>);类型模式 is int? 对非空的装箱底层值同样匹配,因此三行都是 True

关键点: Nullable<T> 不是 CLR 类型,运行时只有“底层值”或“null”两种形态。

0042 以下代码输出什么?

难度: 实战

int? a = null;
int? b = 3;

Console.WriteLine(a + b);   // 1
Console.WriteLine(a < b);   // 2
  • A. 第 1 行输出空行,第 2 行输出 False(提升算术结果为 null;提升关系比较返回 bool,任一为 null 时为 false
  • B. 两行都输出空行
  • C. 两行都输出 False
  • D. 编译失败,null 不能参与运算
查看答案与解析

正确答案A

解析: 提升运算符中,算术(+-*/)任一操作数为 null 结果为 null;关系(<>==)返回的是 bool 而非 bool?,任一为 null 时结果为 false

关键点: 提升关系比较“为假”不等于“为空”,这也是 ?? 经常配合使用的原因。

0043 以下代码输出什么?

难度: 进阶

int? n = null;
int count = 0;
int result = n ?? ++count;

Console.WriteLine(result + "," + count);
  • A. 1,1?? 左侧为 null 时才求值右侧)
  • B. 0,0
  • C. 1,0
  • D. 0,1
查看答案与解析

正确答案A

解析: ?? 是短路运算符,左侧非 null 时右侧不执行;这里左侧为 null,执行 ++countresultcount 都是 1。

关键点: 把有副作用的表达式放在 ?? 右侧时要清楚它可能不执行。

0044 开启可空引用类型(NRT)后,以下代码会怎样?

难度: 进阶

static string? Maybe() => null;

string s = Maybe();
Console.WriteLine(s.Length);
  • A. 编译错误
  • B. 编译成功但有 CS8602 警告(可能为 null 的解引用),运行时抛 NullReferenceException
  • C. 编译成功且无警告
  • D. 编译成功,运行时输出 0
查看答案与解析

正确答案B

解析:string? 赋给 string 触发警告,解引用触发 CS8602;NRT 只是静态分析提示,运行时不生成判空代码,仍会抛 NullReferenceException

关键点: 警告代表“编译器不确定”,不是运行时保护。

0045 以下代码运行结果是什么?

难度: 实战

string? s = null;
string t = s!;
Console.WriteLine(t.Length);
  • A. 编译错误
  • B. 编译有警告,运行正常
  • C. 编译无警告,运行时抛 NullReferenceException
  • D. 编译无警告,运行输出 0
查看答案与解析

正确答案C

解析: !(空值抑制运算符)只告诉编译器“这里不会为 null”,从而消除警告;它不生成任何运行时检查,实际值为 null 时照样抛 NullReferenceException

关键点: ! 是写给编译器看的,不是运行时转换。

0046 以下代码输出什么?

难度: 进阶

Console.WriteLine(default(int?) is null);
Console.WriteLine(default(string) is null);
Console.WriteLine(default(int) is null);
  • A. TrueTrueTrue
  • B. TrueTrueFalseint? 与引用类型的默认值是 nullint 的默认值是 0)
  • C. FalseTrueTrue
  • D. FalseFalseFalse
查看答案与解析

正确答案B

解析: default(int?) 是“无值”的 Nullable<int>is nullTrue;引用类型默认值就是 nulldefault(int) 是 0,不是 null

关键点: default 对值类型与可空值类型含义不同。

0047 以下代码中哪一行能通过编译?

难度: 实战

bool? a = null;
bool? b = true;

var r1 = a & b;    // 1
var r2 = a && b;   // 2
  • A. 第 1 行编译通过(结果为 null),第 2 行编译失败(bool? 不支持短路 &&
  • B. 两行都编译,r1r2 都是 null
  • C. 两行都编译,r1false
  • D. 第 1 行编译失败,第 2 行编译通过
查看答案与解析

正确答案A

解析: &/| 提升到 bool? 后按三值逻辑计算(null & truenull);短路运算符 &&/|| 不支持 bool? 操作数,报 CS0019。

关键点: 需要三值逻辑用 &/|,但要注意结果仍是 bool?

0048 以下代码运行结果是什么?

难度: 实战

object o = null;

int? n = (int?)o;   // 1
int i = (int)o;     // 2
  • A. 两行都抛异常
  • B. 两行都得到 null
  • C. 第 1 行 nnull 不抛异常,第 2 行抛 NullReferenceException
  • D. 第 1 行抛异常,第 2 行得到 0
查看答案与解析

正确答案C

解析: 把值为 nullobject 强制转换为可空值类型得到“无值”的可空值,不抛异常;强转为非可空值类型 int 则抛 NullReferenceException

关键点: 反序列化/反射场景中,(int?)objnull 是安全的写法。

0049 关于 int?string?,哪项说法正确?

难度: 进阶

  • A. 两者都是值类型包装
  • B. int? 是值类型 Nullable<int>,有装箱、提升运算等运行时语义;string? 只是编译期注解,运行时与 string 是同一个类型
  • C. 两者都会改变运行时类型
  • D. string?Nullable<string> 的包装
查看答案与解析

正确答案B

解析: Nullable<T> 是真实的值类型,参与装箱、提升运算;可空引用类型注解只是编译期元数据,不影响运行时类型,也不会产生运行时检查。

关键点: 同名“可空”,一个是运行时机制,一个是静态分析约定。

0050 关于 x == nullx is null,哪项正确?

难度: 进阶

  • A. 两者完全等价
  • B. is null 也会调用重载的 ==
  • C. is null 是模式匹配,不参与运算符重载决议;== 可能被重载,对自定义类型行为可能不同
  • D. x == null 永远不会被重载
查看答案与解析

正确答案C

解析: == 是运算符,可被类型重载(如 stringdecimal 或自定义类型);is null 是模式匹配,直接做空判断,不触发重载。

关键点: 对可能重载 == 的类型,优先用 is null 表达“真的是 null”。

0051 以下代码输出什么?

难度: 实战

int? a = null;
a++;

int? b = 3;
b++;

Console.WriteLine(a);
Console.WriteLine(b);
  • A. 两行都输出空行
  • B. 输出 04
  • C. 编译失败
  • D. 第一行输出空行(null 自增后仍是 null),第二行输出 4
查看答案与解析

正确答案D

解析: 提升的 ++:可空值为 null 时保持 null,有值时对底层值自增。a 输出空行,b 输出 4。

关键点: 对可空值类型自增前先判断是否有值。

0052 以下代码输出什么?

难度: 进阶

int? n = null;
string s = null;

Console.WriteLine("n=" + n + ", s=" + s);
  • A. n=, s=
  • B. n=null, s=null
  • C. 编译失败
  • D. n=0, s=
查看答案与解析

正确答案A

解析: 字符串拼接对 null 按空串处理:"n=" + null"n="s 同理,结果 n=, s=

关键点: 拼接或插值时 null 输出为空,而不是字符串 "null"

0053 开启 NRT 后,以下代码会怎样?

难度: 进阶

class Order
{
    public string Customer { get; set; }
}
  • A. 编译错误
  • B. 编译成功但有 CS8618 警告(非空属性未在构造函数中初始化)
  • C. 编译成功且无警告
  • D. 编译成功,运行时自动初始化为空串
查看答案与解析

正确答案B

解析: 非空引用类型属性在构造函数中未初始化会触发 CS8618;实际运行时该属性默认仍是 null,读取可能得到 null

关键点: 警告提示“契约可能被破坏”,不是运行时默认值机制。

0054 以下代码能否通过编译?

难度: 实战

static void M<T>(T value) where T : struct { }

M<int?>(null);
  • A. 编译成功
  • B. 运行抛异常
  • C. 编译失败,Nullable<int> 不满足 struct 约束
  • D. 编译成功,但参数永远是 null
查看答案与解析

正确答案C

解析: where T : struct 约束不接受可空值类型作为类型实参:int? 本身不满足该约束,编译报错。

关键点: 约束 T : structT : notnull/unmanaged 对可空值类型的处理不同。

0055 关于可空引用类型的编译期警告,哪项正确?

难度: 进阶

  • A. 警告在运行时会被强制检查
  • B. 警告只是编译期提示,运行时不产生任何检查,仍可能 NullReferenceException
  • C. 警告会阻止编译
  • D. 开启 NRT 后所有解引用都会自动判空
查看答案与解析

正确答案B

解析: NRT 的警告是纯静态分析产物,不生成运行时判空代码;该抛 NullReferenceException 的地方照常抛。

关键点: 把 NRT 当“契约标注”,不要当“运行时保护”。

0056 以下代码为什么需要 ??=

难度: 实战

var map = new Dictionary<string, List<int>>();
map.TryGetValue("k", out var list);

list ??= new List<int>();
list.Add(1);
  • A. TryGetValueout 参数带 [MaybeNullWhen(false)],查找失败时是 null??= 只在为 null 时创建
  • B. 不需要 ??=out 参数失败时自动是空集合
  • C. ??= 在这里会把 list 置为 null
  • D. 第 2 行已经抛异常,不会执行到 ??=
查看答案与解析

正确答案A

解析: TryGetValue 失败时把 out 置为 null,配合 [MaybeNullWhen(false)] 注解,编译器把它视为可空;list ??= new List<int>() 只在为 null 时新建,是“取或建”的标准写法。

关键点: 可空分析让 out 的 null 风险显式化,??= 是推荐兜底。

0057 以下代码输出什么?

难度: 进阶

List<int>? list = null;
int? count = list?.Count;

Console.WriteLine(count ?? -1);
  • A. 0
  • B. null
  • C. -1?. 使结果类型变成 int?,为 null?? 生效)
  • D. 编译失败
查看答案与解析

正确答案C

解析: 空条件运算符会让表达式结果提升为可空类型:list?.Count 的类型是 int?listnull 时结果是 null?? -1 输出 -1

关键点: ?. 的结果可能“吃掉”原来的非空类型,注意与 ?? 配合。

0058 以下代码输出什么?

难度: 实战

static T? GetDefault<T>() => default;

Console.WriteLine(GetDefault<int>() == null);
Console.WriteLine(GetDefault<string>() is null);
  • A. FalseTrue(无约束时 T? 表示“可 default”:值类型结果是 0,引用类型才是 null
  • B. TrueTrue
  • C. FalseFalse
  • D. 编译失败
查看答案与解析

正确答案A

解析: C# 9 起无约束泛型的 T? 表示“可 default”并反映在注解上:T 为值类型时 default 是 0(== nullFalse),引用类型时是 null

关键点: 无约束 T?int?/string? 语义都不同,最容易在泛型工具方法里踩坑。

0059 以下代码运行结果是什么?

难度: 进阶

int? n = null;

try
{
    Console.WriteLine(n.Value);
}
catch (Exception ex)
{
    Console.WriteLine(ex.GetType().Name);
}
  • A. 0
  • B. null
  • C. NullReferenceException
  • D. InvalidOperationException(无值可空值类型访问 Value 抛该异常)
查看答案与解析

正确答案D

解析: 无值可空值类型访问 .ValueInvalidOperationException;判空应使用 HasValueTryGetValue 模式或 ??

关键点: .Value 是“我确定有值”的强断言,出错类型与 NullReferenceException 不同。

0060 以下代码输出什么?

难度: 进阶

int? n = null;
string s = null;

Console.WriteLine($"n={n}, s={s}");
  • A. n=, s=null 在插值中格式化为空)
  • B. n=null, s=null
  • C. 编译失败
  • D. n=0, s=null
查看答案与解析

正确答案A

解析: 字符串插值对 null 值格式化为空字符串(内部走 IFormattable/ToStringnull 的空处理),结果 n=, s=

关键点: 与 0052 的拼接行为一致:null 插值为空。

官方资料

当前分类

C# 选择题

查看全部分类 →
  1. 01C# 试题 01:变量、常量与类型推断20 题
  2. 02C# 试题 02:数值类型与转换20 题
  3. 03C# 试题 03:可空类型与空值分析20 题
  4. 04C# 试题 04:运算符与表达式20 题
  5. 05C# 试题 05:流程控制20 题
ESC

输入关键词开始搜索