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

C# 试题 27:LINQ 延迟执行

0521 以下代码输出什么?

难度: 实战

var list = new List<int> { 1, 2, 3 };
var query = list.Where(x => x > 1);
list.Add(4);

Console.WriteLine(string.Join(",", query));
  • A. 2,3,4,查询在枚举时才读取源,看到新增元素
  • B. 2,3
  • C. 1,2,3,4
  • D. 3,4
查看答案与解析

正确答案A

解析: Where 只构建查询,不读取源;真正执行发生在 string.Join 枚举时,此时源里已有 4,因此结果为 2、3、4。延迟执行最常见的坑就是“以为查询在定义时已固定”。

关键点: 查询是惰性的,源的变化会反映到枚举结果。

0522 以下代码输出什么?

难度: 进阶

var n = 0;
var query = Enumerable.Range(1, 3).Select(x => { n++; return x; });

Console.WriteLine(query.Count());
Console.WriteLine(query.Count());
Console.WriteLine(n);
  • A. 3 / 3 / 3
  • B. 3 / 3 / 0
  • C. 3 / 3 / 6,每次 Count() 都重新枚举并执行委托
  • D. 3 / 0 / 3
查看答案与解析

正确答案C

解析: Count() 会强制枚举整个序列,而查询每次枚举都重新执行 Select 的委托。两次 Count() 各执行 3 次,n 累计为 6。带副作用的查询被多次消费是生产事故的常见来源。

关键点: 延迟查询的副作用会随每次枚举重复发生。

0523 以下代码输出什么?

难度: 实战

var n = 0;
var list = Enumerable.Range(1, 3).Select(x => { n++; return x; }).ToList();

Console.WriteLine(list.Count());
Console.WriteLine(list.Count());
Console.WriteLine(n);
  • A. 3 / 3 / 6
  • B. 3 / 3 / 3,ToList 物化一次,之后统计的是内存列表
  • C. 3 / 0 / 3
  • D. 3 / 3 / 0
查看答案与解析

正确答案B

解析: ToList() 立即枚举并物化,Select 委托只执行 3 次;之后对内存列表的两次 Count() 不再触碰原查询,n 保持 3。需要多次消费时先物化是标准做法。

关键点: 物化(ToList/ToArray)切断与延迟查询的绑定。

0524 以下代码输出什么?

难度: 进阶

var n = 0;
var query = Enumerable.Range(1, 100).Select(x => { n++; return x; });

query.Any(x => x == 3);
Console.WriteLine(n);
  • A. 100
  • B. 1
  • C. 0
  • D. 3,Any 找到第一个匹配即短路,只读取了前 3 个元素
查看答案与解析

正确答案D

解析: Any 在谓词首次返回 true 时立即停止枚举:依次读 1、2、3,x==3 命中,n 为 3。若用 Count(x => x == 3) > 0 则会遍历全部 100 个元素。

关键点: Any 短路,Count 全量,判断存在性不要用 Count。

0525 对静态类型为 IEnumerable<int>、实际是惰性序列的 source,判断“是否非空”用 source.Any() 还是 source.Count() > 0,哪项正确?

难度: 进阶

  • A. 两者等价,复杂度相同
  • B. Any() 在第一个元素处短路;Count() 会枚举整个序列(若对象不是 ICollection),对无限序列 Count() 永不返回
  • C. Count() 更快,因为它不执行谓词
  • D. Any() 一定抛异常
查看答案与解析

正确答案B

解析: Any() 只需推进一次迭代器即返回;Count() > 0 在源不是 ICollection 时会完整遍历,无限序列上直接挂死。语义上 Any 表达“存在元素”,Count 表达“元素个数”,别用后者表达前者。

关键点: 判空用 Any(),尤其源可能是无限或昂贵时。

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

难度: 实战

Console.WriteLine(new int[0].First());
  • A. 输出 0
  • B. 输出 null
  • C. 运行抛 InvalidOperationException(序列不含元素)
  • D. 编译失败
查看答案与解析

正确答案C

解析: First() 对空序列抛 InvalidOperationException,不返回默认值。只有 FirstOrDefault 才在空序列时返回 default,两者契约不同,混用是经典失误。

关键点: First 与 FirstOrDefault 只差一个 OrDefault,行为差一个异常。

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

难度: 实战

var query = new[] { 1, 2, 3 }.Where(x => x > 0);

Console.WriteLine(query.Single());
  • A. 运行抛 InvalidOperationException(序列包含多个元素)
  • B. 输出 1
  • C. 输出 3
  • D. 输出 1,Single 取第一个
查看答案与解析

正确答案A

解析: Single() 的契约是“恰好一个”,多于一个或为零都抛 InvalidOperationExceptionSingle 不“取第一个”,取第一个是 First 的职责。

关键点: Single 是断言而非选择,失败即抛异常。

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

难度: 实战

Console.WriteLine(new int[0].SingleOrDefault());
Console.WriteLine(new[] { 1, 2 }.SingleOrDefault());
  • A. 0 / 1
  • B. 0 / 2
  • C. 1 / 2
  • D. 第一行输出 0;第二行抛 InvalidOperationException,SingleOrDefault 只在“恰好一个”时成功
查看答案与解析

正确答案D

解析: SingleOrDefault 只在空序列时返回默认值;序列包含多个元素时仍抛 InvalidOperationException。它与 FirstOrDefault 的容错范围不同,不能想当然地“有多个就取第一个”。

关键点: OrDefault 只豁免“空”,不豁免“多”。

0529 以下代码输出什么?

难度: 进阶

var query = new[] { 1, 2, 3, 4 }.Where(x => { Console.Write(x); return x % 2 == 0; });

Console.Write(query.First());
  • A. 24
  • B. 122,Where 依次读取 1、2,命中后 First 立即返回 2
  • C. 12342
  • D. 12
查看答案与解析

正确答案B

解析: First() 推进管道直到拿到第一个匹配:Where 读取 1(打印 1,不匹配)、读取 2(打印 2,匹配)并产出,First 返回 2(打印 2)。输出为 122,后面 3、4 从未被读取。

关键点: 管道元素按需流动,短路的运算符决定读取边界。

0530 以下代码输出什么?

难度: 进阶

var funcs = new List<Func<int>>();
for (int i = 0; i < 3; i++) funcs.Add(() => i);

Console.WriteLine(string.Join(",", funcs.Select(f => f())));
  • A. 0,1,2
  • B. 2,2,2
  • C. 3,3,3,for 的循环变量是单一共享变量,闭包捕获同一变量
  • D. 编译失败
查看答案与解析

正确答案C

解析: for 的循环变量在整个循环期间是同一个变量,三个 lambda 捕获的都是它,调用时它已是 3,因此输出三个 3。这与 foreach(C# 5 起每迭代独立变量)形成对比。

关键点: for 闭包共享变量,foreach 闭包每迭代独立。

0531 以下代码输出什么?

难度: 实战

var funcs = new List<Func<int>>();
foreach (var i in Enumerable.Range(0, 3)) funcs.Add(() => i);

Console.WriteLine(string.Join(",", funcs.Select(f => f())));
  • A. 0,1,2,C# 5 起 foreach 每次迭代使用独立变量
  • B. 3,3,3
  • C. 2,2,2
  • D. 编译失败
查看答案与解析

正确答案A

解析: 自 C# 5 起,foreach 的迭代变量每轮迭代都是新变量,闭包捕获各自的值,输出 0、1、2。这正是 0530 与 0531 的对照:循环形式决定闭包行为。

关键点: foreach 已修复共享变量陷阱,for 没有。

0532 以下代码输出什么?

难度: 实战

var funcs = new List<Func<int>>();
for (int i = 0; i < 3; i++)
{
    int j = i;
    funcs.Add(() => j);
}

Console.WriteLine(string.Join(",", funcs.Select(f => f())));
  • A. 3,3,3
  • B. 2,2,2
  • C. 编译失败
  • D. 0,1,2,局部副本 j 每迭代独立
查看答案与解析

正确答案D

解析: 在循环体内声明局部变量 j 并复制 i,每个闭包捕获各自的 j,互不影响,输出 0、1、2。这是 for 循环闭包的经典修正写法。

关键点: 需要按值捕获时,复制到循环体内局部变量。

0533 以下代码输出什么?

难度: 进阶

var list = new List<int> { 3, 1, 2 };
var query = list.OrderBy(x => x);
list.Add(0);

Console.WriteLine(string.Join(",", query));
  • A. 3,1,2,0
  • B. 0,1,2,3,OrderBy 延迟执行,枚举时才读取并排序当前源
  • C. 3,1,2
  • D. 0,1,2,排序在调用 OrderBy 时已完成
查看答案与解析

正确答案B

解析: OrderBy 是延迟运算符:调用时不排序,枚举时才缓冲全部元素并排序。此时源已包含新增的 0,输出 0,1,2,3。注意排序虽延迟,但枚举时必须完整读取源(非流式)。

关键点: 延迟不等于立即执行,也别假设它是流式。

0534 以下代码输出什么?

难度: 实战

var list = new List<int> { 1, 2 };
var query = list.Select(x => x * 10);

Console.WriteLine(string.Join(",", query));
list.Add(3);
Console.WriteLine(string.Join(",", query));
  • A. 10,20 / 10,20
  • B. 10,20,30 / 10,20,30
  • C. 10,20 / 10,20,30,每次枚举重新执行查询
  • D. 10,20 / 抛异常
查看答案与解析

正确答案C

解析: 两次 string.Join 各触发一次完整枚举,第二次枚举时源已多出 3,得到 10,20,30。同一查询对象被重复枚举可能产生不同结果,这是延迟执行的自然推论。

关键点: 查询对象本身无状态,结果取决于枚举那一刻的源。

0535 关于 LINQ 运算符的立即/延迟执行,哪项正确?

难度: 进阶

  • A. Where 调用时立即枚举源并缓存结果
  • B. OrderBy 调用时立即完成排序
  • C. GroupBy 调用后源已被完整读取
  • D. Count() 调用时枚举整个源;Where/Select/OrderBy 返回的查询在枚举前不执行
查看答案与解析

正确答案D

解析: LINQ 运算符分两类:Where/Select/OrderBy/GroupBy 等是延迟执行(返回查询),ToList/ToArray/Count/First 等会立即驱动枚举。GroupBy 虽延迟,但枚举时会一次性缓冲整个源。

关键点: “调用即执行”与“调用只组装查询”要先分清。

0536 source 静态类型为 IEnumerable<int>,实际对象是 List<int>。调用 source.Count() 的时间复杂度是?

难度: 进阶

  • A. O(1),Count() 检测到对象实现 ICollection<int> 后直接读 Count 属性
  • B. O(n),Count() 总是全量枚举
  • C. O(n log n)
  • D. 抛 InvalidOperationException
查看答案与解析

正确答案A

解析: Enumerable.Count() 内部先做 ICollection<T>/ICollection 探测,命中就直接返回 Count 属性,不枚举。因此“Count() 一定 O(n)”是误解;但对自定义惰性序列(非 ICollection)仍是全量枚举。

关键点: Count() 对 ICollection 有优化,对纯 IEnumerable 才全量。

0537 以下代码输出什么?

难度: 实战

Console.WriteLine(Enumerable.Empty<int>().Any());
Console.WriteLine(Enumerable.Empty<int>().All(x => x > 0));
  • A. True / False
  • B. False / False
  • C. False / True,All 对空序列恒真(空真)
  • D. True / True
查看答案与解析

正确答案C

解析: Any() 要求至少一个元素,空序列为 false;All() 要求所有元素满足谓词,空序列没有反例,按逻辑学“空真(vacuous truth)”返回 true。用 All 判断“每个都满足”时要注意空序列的隐式通过。

关键点: 空序列上 All 为 true 常被忽视。

0538 以下代码输出什么?

难度: 进阶

var query = new[] { 1, 2, 3, 4, 5 }.Select(x => { Console.Write(x); return x; });

query.Take(2).ToList();
  • A. 12345,Take 也会遍历全部
  • B. 12,Take(2) 取到两个元素后停止,不再读取源
  • C. 1234
  • D. 无输出
查看答案与解析

正确答案B

解析: Take(2) 在拿到两个元素后停止推进源迭代器,Select 的委托只执行两次,输出 12。这既是延迟执行的体现,也是“Take 提前终止”可以避免昂贵源计算的原因。

关键点: Take 短路上游管道,未消费部分不执行。

0539 以下代码输出什么?

难度: 实战

int threshold = 2;
var query = new[] { 1, 2, 3, 4 }.Where(x => x > threshold);
threshold = 3;

Console.WriteLine(string.Join(",", query));
  • A. 3,4
  • B. 2,3,4
  • C. 1,2,3,4
  • D. 4,谓词在枚举时求值,读取最新 threshold
查看答案与解析

正确答案D

解析: Where 的谓词闭包捕获的是 threshold 变量本身而非其值,枚举时 threshold 已是 3,只有 4 满足 x > 3。闭包捕获的“变量”在延迟执行中读的是最新值。

关键点: 谓词闭包看的是枚举时的变量状态。

0540 以下代码输出什么?

难度: 实战

var query = new[] { "a", "b" }.Where(s => s.Length > 5);
var result = query.FirstOrDefault();

Console.WriteLine(result is null ? "null" : result);
  • A. null,FirstOrDefault 无匹配时返回 null(引用类型默认值)
  • B. ""
  • C. 抛 InvalidOperationException
  • D. "a"
查看答案与解析

正确答案A

解析: 谓词无匹配时序列为空,FirstOrDefault 返回 default(string) 即 null。对引用类型,OrDefault 的“默认值”就是 null,使用前判空是必须的。

关键点: FirstOrDefault 的默认值是类型默认值,引用类型即 null。

官方资料

当前分类

C# 选择题

查看全部分类 →
  1. 25C# 试题 25:Dictionary、HashSet 与相等性20 题
  2. 26C# 试题 26:有序、并发与不可变集合20 题
  3. 27C# 试题 27:LINQ 延迟执行20 题
  4. 28C# 试题 28:LINQ 分组与连接20 题
  5. 29C# 试题 29:迭代器与异步流20 题
ESC

输入关键词开始搜索