C# 试题 44:C# 10~12 新特性
0861 以下代码能否编译?
难度: 进阶
namespace Demo
{
global using System;
}
- A. 编译通过,全局 using 可以写在任意位置
- B. 编译通过,但只对 Demo 命名空间生效
- C. 编译通过,但需要再写一次非全局 using
- D. 编译失败,global using 必须位于文件顶层、命名空间之外,且先于其他 using
查看答案与解析
正确答案D
解析: global using 只能出现在编译单元顶层(命名空间之外),且必须位于其他非全局 using 之前;写在命名空间内直接编译失败。
关键点: 全局 using 是“文件级”声明,不是“命名空间级”声明。
0862 以下代码能否编译?
难度: 实战
using System.Collections.Generic;
global using System;
class C { }
- A. 编译通过
- B. 编译失败,global using 必须位于所有非 global using 之前
- C. 编译通过,但 global using 被忽略
- D. 编译通过,两个 using 作用域相同
查看答案与解析
正确答案B
解析: 规则要求 global using 指令必须排在其他 using 指令前面;先写非全局 using 再写 global using 会编译失败。
关键点: global using 有严格的书写位置要求。
0863 关于 global using 的作用域,哪项正确?
难度: 实战
- A. 对当前项目(编译单元)内所有文件生效,不影响引用该项目的其他项目
- B. 仅对同一目录下的文件生效
- C. 对所有引用该项目的项目也生效
- D. 仅对声明它的文件生效
查看答案与解析
正确答案A
解析: 全局 using 的作用域是当前编译单元,即当前项目内的所有源文件;它不会通过项目引用传播到其他项目,其他项目需要各自声明。
关键点: global using 只在本项目内全局。
0864 以下代码能否编译?
难度: 实战
class A { }
namespace Demo;
- A. 编译通过,A 属于全局命名空间
- B. 编译通过,A 属于 Demo
- C. 编译失败,文件作用域命名空间必须位于文件中所有成员声明之前
- D. 编译通过,但 namespace 被忽略
查看答案与解析
正确答案C
解析: 文件作用域命名空间必须是文件中(除 using、注释等)的第一个声明;在它之前声明类型属于非法顺序,编译失败。
关键点: 文件作用域命名空间必须在成员声明之前。
0865 以下代码能否编译?
难度: 进阶
namespace A;
namespace B { }
- A. 编译通过,两个命名空间共存
- B. 编译失败,文件作用域命名空间与块作用域命名空间不能在同一文件中混用
- C. 编译通过,B 嵌套在 A 中
- D. 编译通过,但 B 被忽略
查看答案与解析
正确答案B
解析: 一个源文件只能使用一种命名空间形式:要么文件作用域、要么块作用域;混用两种声明方式编译失败(一个文件也只能有一个文件作用域命名空间)。
关键点: 文件作用域与块作用域命名空间互斥。
0866 以下代码中 A、B 两个类属于哪个命名空间?
难度: 实战
namespace Demo;
class A { }
class B { }
- A. A 属于全局命名空间,B 属于 Demo
- B. 编译失败,文件作用域命名空间后不能声明类
- C. A 属于 Demo,B 属于全局命名空间
- D. 文件其余部分都属于 Demo,A、B 都是 Demo 的成员
查看答案与解析
正确答案D
解析: 文件作用域命名空间的“作用域”延伸到文件末尾,声明之后所有类型都隐式属于该命名空间,且不需要花括号与缩进。
关键点: 文件作用域命名空间接管整个剩余文件。
0867 以下代码输出什么?
难度: 实战
var p = new Person { Name = "Ada" };
Console.WriteLine(p.Name);
class Person
{
public required string Name { get; init; }
}
- A. 输出
Ada,对象初始化器满足 required 要求 - B. 编译失败,required 不能用于 init
- C. 运行抛
MissingFieldException - D. 输出空串
查看答案与解析
正确答案A
解析: required 成员必须在对象构造时由初始化器或带 [SetsRequiredMembers] 的构造函数赋值;用对象初始化器提供 Name 即满足契约,编译通过并输出 Ada。
关键点: 对象初始化器是满足 required 的合法途径。
0868 以下代码能否编译?
难度: 实战
var p = new Person();
class Person
{
public required string Name { get; init; }
}
- A. 编译通过,运行时 Name 为 null
- B. 编译通过,Name 自动初始化为空串
- C. 编译失败,缺少 required 成员 Name
- D. 运行抛
NullReferenceException
查看答案与解析
正确答案C
解析: new Person() 没有为 required 成员 Name 提供值,编译器报 CS9035 错误,阻止编译通过。required 的核心价值就是把“忘了初始化”从运行时问题变成编译期错误。
关键点: required 是编译期强制的初始化契约。
0869 以下代码输出什么?
难度: 进阶
var p = (Person)Activator.CreateInstance(typeof(Person))!;
Console.WriteLine(p.Name ?? "null");
class Person
{
public required string Name { get; init; }
}
- A. 编译失败,反射也无法绕过 required
- B. 编译通过,输出
null;required 只在编译期强制,反射创建不会校验 - C. 运行抛
MissingMemberException - D. 编译通过,输出空串
查看答案与解析
正确答案B
解析: required 是编译期契约,运行时的反射、反序列化等路径不会自动校验;反射创建出的实例 Name 保持 null,程序照常运行。依赖 required 做防御时要意识到它拦不住反射。
关键点: required 只约束编译期,不约束运行时。
0870 以下代码输出什么?
难度: 进阶
var p = new Person();
Console.WriteLine(p.Name ?? "null");
class Person
{
public required string Name { get; init; }
[SetsRequiredMembers]
public Person() { }
}
- A. 编译失败,[SetsRequiredMembers] 不能用于无参构造器
- B. 编译失败,必须显式设置 Name
- C. 编译通过,输出空串
- D. 编译通过,输出
null;[SetsRequiredMembers] 只是声明“已设置全部 required 成员”,编译期豁免,不保证运行时真正赋值
查看答案与解析
正确答案D
解析: [SetsRequiredMembers] 告诉编译器“该构造函数会设置所有 required 成员”,从而免除调用点的检查,但编译器不验证构造函数体内是否真的赋值,运行时 Name 仍是 null。
关键点: SetsRequiredMembers 是信任声明,不是运行时保证。
0871 以下代码能否编译?
难度: 进阶
var p = new Point(3, 4);
Console.WriteLine(p.Sum());
Console.WriteLine(p.x);
class Point(int x, int y)
{
public int Sum() => x + y;
}
- A. 编译失败,类的主构造函数参数不会自动生成同名属性,p.x 无法访问
- B. 输出
7与3 - C. 输出
7与0 - D. 输出
7,p.x 有警告但可运行
查看答案与解析
正确答案A
解析: 对普通 class(非 record),主构造函数参数只是参数,被成员体使用时以私有字段形式捕获,但不会生成公开属性;p.x 编译失败。想公开数据要用 record 或显式声明属性。
关键点: 类的主构造函数参数默认不是属性。
0872 以下代码哪项正确?
难度: 进阶
var r = new R(1);
var c = new C(2);
Console.WriteLine(r.X);
Console.WriteLine(c.X);
record R(int X);
class C(int X);
- A. 输出
1与2 - B. 输出
1与0 - C. 编译失败:c.X 无法访问。record 的主构造函数参数生成同名属性,class 不会
- D. 两行都编译失败
查看答案与解析
正确答案C
解析: record 的主构造函数参数会自动生成同名只读属性(R.X 可访问);普通 class 不生成,c.X 编译失败。这是 record 与 class 主构造函数最本质的差异。
关键点: 只有 record 会从主构造函数参数生成属性。
0873 以下代码输出什么?
难度: 实战
var c = new Counter(5);
Console.WriteLine(c.Next());
Console.WriteLine(c.Next());
class Counter(int start)
{
private int _current = start;
public int Next() => _current++;
}
- A. 输出
0与1 - B. 输出
5与6,主构造函数参数在字段初始化器中可见,_current 捕获 start 的值 - C. 输出
6与7 - D. 编译失败,字段初始化器不能引用主构造函数参数
查看答案与解析
正确答案B
解析: 主构造函数参数在成员初始化和成员体中可见;_current = start 用传入的 5 初始化字段,因此连续调用 Next() 输出 5、6。
关键点: 主构造函数参数可以参与字段初始化。
0874 以下代码能否编译?
难度: 进阶
class Base(int v)
{
protected int GetV() => v;
}
class Derived : Base
{
public Derived() : base(1) { }
public int ReadV() => v;
}
- A. 编译通过,输出 1
- B. 编译通过,v 默认为 0
- C. 运行抛
NullReferenceException - D. 编译失败,基类主构造函数参数对派生类不可见
查看答案与解析
正确答案D
解析: 基类主构造函数参数被捕获为基类的私有字段,派生类无法直接访问 v;派生类只能通过基类暴露的成员或构造函数传参使用它。
关键点: 主构造函数参数不会“泄漏”给派生类。
0875 以下代码能否编译?
难度: 进阶
class Point(int x)
{
public Point() { }
}
- A. 编译失败,带主构造函数的类型中,其他构造函数必须通过 this(…) 链接主构造函数
- B. 编译通过,两个构造函数并存
- C. 编译通过,无参构造器自动调用主构造函数
- D. 运行抛
MissingMethodException
查看答案与解析
正确答案A
解析: 类型带主构造函数后,所有其他构造函数必须显式用 : this(...) 链接主构造函数(否则参数无法获得来源),编译器报错。
关键点: 附加构造函数必须 this(…) 链到主构造函数。
0876 以下代码能否编译?
难度: 进阶
var list = [1, 2, 3];
- A. 编译通过,推断为 int[]
- B. 编译通过,推断为
List<int> - C. 编译失败,集合表达式需要目标类型,不能用 var 推断
- D. 编译通过,推断为
IEnumerable<int>
查看答案与解析
正确答案C
解析: 集合表达式 [...] 没有固定的固有类型,必须由目标类型决定(数组、List、Span 等);用 var 无法推断目标类型,编译器报 CS9176。
关键点: 集合表达式必须显式给出目标类型。
0877 以下代码输出什么?
难度: 实战
int[] first = [1, 2];
int[] all = [0, .. first, 3];
Console.WriteLine(string.Join(",", all));
- A. 输出
1,2,3 - B. 输出
0,1,2,3,.. 展开元素把 first 的元素展开进新集合 - C. 输出
0,3 - D. 编译失败,.. 只能用于数组
查看答案与解析
正确答案B
解析: 集合表达式的展开元素 .. first 会把可迭代对象 first 的元素逐个展开,与字面元素 0、3 一起组成 [0,1,2,3]。
关键点: .. 是集合表达式的展开语法。
0878 以下代码输出什么?
难度: 实战
Span<int> s = [1, 2, 3];
Console.WriteLine(s.Length);
- A. 输出
0 - B. 编译失败,集合表达式不能转换为 Span
- C. 抛
InvalidOperationException - D. 输出
3,集合表达式可以转换为Span<T>等目标类型
查看答案与解析
正确答案D
解析: 集合表达式可以转换为 Span<T>/ReadOnlySpan<T> 等目标类型(编译器按目标类型生成栈上或暂存数组);这里 s 含 3 个元素,Length 为 3。
关键点: 集合表达式的目标类型包括 ref struct。
0879 关于 C# 12 集合表达式可转换的目标类型,哪项正确?
难度: 实战
- A. 可转换为数组、
List<T>、Span<T>、ImmutableArray<T>等,但必须有明确目标类型,var 无法推断 - B. 只能转换为数组
- C. 只能转换为
List<T> - D. 只能用于方法返回值的类型推断
查看答案与解析
正确答案A
解析: 集合表达式是“类型无关”的语法,编译器按目标类型生成对应实现:数组、List<T>、Span<T>、ImmutableArray<T> 等都支持;没有目标类型(如 var)就无法编译。
关键点: 目标类型决定集合表达式的最终形态。
0880 关于 C# 12 类的主构造函数(class Point(int x, int y)),哪项使用建议正确?
难度: 实战
- A. 主构造函数参数会自动生成公开属性,适合直接暴露数据
- B. 主构造函数参数等价于 readonly 字段
- C. 类的主构造函数参数默认不生成属性,适合短生命周期、仅内部使用的场景;需要公开数据时用 record 或显式声明属性
- D. 主构造函数只能在 record 上使用
查看答案与解析
正确答案C
解析: 普通类的主构造函数参数只是参数,不会生成公开属性,因此适合依赖注入、短生命周期对象等“用完即弃”的场景;需要把参数暴露成公开数据时,应改用 record(自动生成属性)或显式声明属性。
关键点: 主构造函数是参数机制,不是属性机制。