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

C# 试题 46:C# 14 新特性

0901 以下代码输出什么?

难度: 实战

class Counter
{
    public int Value
    {
        get => field;
        set => field = value;
    }
}

Console.WriteLine(new Counter { Value = 3 }.Value);
  • A. 编译失败,属性访问器中不能引用 field
  • B. 输出 3,field 引用编译器为该属性合成的后备字段
  • C. 输出 0
  • D. 运行抛 StackOverflowException
查看答案与解析

正确答案B

解析: C# 14 的 field 上下文关键字在属性访问器中指向编译器生成的合成后备字段:get => field 直接读它,set => field = value 写它,不再需要手写 _value 字段。赋值 Value = 3 落到后备字段,输出 3。

关键点: field 是访问器内引用合成后备字段的快捷方式。

0902 以下代码输出什么(注意类中已有名为 field 的成员)?

难度: 进阶

class C
{
    int field = 5;

    public int X { get => field; }
}

Console.WriteLine(new C().X);
  • A. 输出 5,field 引用类中已有字段
  • B. 编译失败,关键字与成员名冲突
  • C. 输出 0 并产生警告 CS9258:field 仍绑定到合成的后备字段,想引用现有成员需写 this.field@field
  • D. 运行抛 NullReferenceException
查看答案与解析

正确答案C

解析: 在访问器中 field 优先按上下文关键字处理,绑定到合成的后备字段(初始值为 0),同时编译器给出 CS9258 警告提示冲突;类中那个 field = 5 的成员变成未使用。要引用现有成员必须显式写 this.field@field。这是资深开发者最容易在存量代码上踩到的兼容性坑。

关键点: 已有 field 成员会让 field 的语义静默改变,需 this.field 消除歧义。

0903 以下代码能否编译?

难度: 实战

class C
{
    public int X { get => field; set => field = value; }

    public int Get() => field;
}
  • A. 编译失败 CS0103:field 只存在于属性访问器中,普通方法里找不到该名称
  • B. 编译通过,Get() 返回合成后备字段
  • C. 编译通过,但运行抛异常
  • D. 编译失败,field 与属性名 X 冲突
查看答案与解析

正确答案A

解析: field 的作用域限定在属性(或索引器)的访问器体内,普通方法、构造函数等位置没有这个名称,Get() 里引用 field 报 CS0103。想暴露后备字段只能走属性本身或手动声明真正的字段。

关键点: field 不是类级别成员,访问器之外不可见。

0904 关于 field 关键字的语义,哪项表述正确?

难度: 进阶

  • A. field 可以在类的任意方法中访问所有属性的后备字段
  • B. 属性已有显式后备字段时,field 自动指向该显式字段
  • C. field 仅适用于 class,不适用于 struct 与记录
  • D. field 是仅限属性访问器使用的上下文关键字;与现有成员 field 冲突时关键字优先并产生警告,可用 this.field/@field 引用成员
查看答案与解析

正确答案D

解析: field 只在访问器内生效且绑定到合成后备字段;显式字段场景下不存在“自动指向”,仍以合成字段为准(冲突时靠警告提示)。struct 中同样可用。冲突处理用 this.field@field 显式引用成员是最稳妥的写法。

关键点: field 的绑定规则是“合成字段优先 + 冲突警告”。

0905 以下代码输出什么?

难度: 实战

public static class StringExt
{
    extension(string s)
    {
        public int WordCount => s.Split(' ').Length;
    }
}

Console.WriteLine("a b c".WordCount);
  • A. 编译失败,扩展块内只能声明扩展方法
  • B. 输出 3,C# 14 扩展块可以声明扩展属性
  • C. 输出 0
  • D. 编译失败,扩展属性必须先有实例字段
查看答案与解析

正确答案B

解析: C# 14 的扩展成员块 extension (string s) { ... } 除了扩展方法,还能声明扩展属性、索引器等成员,块参数 s 即接收者。"a b c".WordCount 走扩展属性求值,Split(' ') 得到 3 段,输出 3。扩展成员按静态绑定调用,不修改 string 类型本身。

关键点: 扩展块成员以块参数为接收者,属性等成员同样可用。

0906 以下代码能否编译?

难度: 进阶

public static class Ext
{
    extension(string s)
    {
        private int _count;
    }
}
  • A. 编译失败 CS9282:扩展块中不允许实例字段,扩展成员没有实例状态
  • B. 编译通过,扩展块支持私有实例状态
  • C. 编译通过,但运行抛异常
  • D. 编译失败,extension 关键字不存在
查看答案与解析

正确答案A

解析: 扩展成员本质是静态绑定、作用在被扩展类型上的“视图”,编译器不会为被扩展类型注入任何实例字段,因此扩展块里声明字段直接报 CS9282。需要状态时只能通过接收者自身或外部字典等途径维护。

关键点: 扩展成员无实例状态,“给类型加字段”是错误直觉。

0907 以下代码能否编译?

难度: 进阶

class Box
{
    extension(string s)
    {
        public int Len => s.Length;
    }
}
  • A. 编译通过,扩展只对 string 生效
  • B. 编译通过,但只能在该类内部调用
  • C. 编译失败 CS9283:扩展必须在顶级非泛型静态类中声明
  • D. 运行抛 TypeLoadException
查看答案与解析

正确答案C

解析: 扩展块和扩展方法一样,必须声明在“顶级非泛型静态类”中;写在普通实例类里报 CS9283。这是编译器对扩展成员归属的硬性要求,与被扩展类型是 string 无关。

关键点: 扩展块的宿主必须是顶级非泛型静态类。

0908 关于 C# 14 扩展成员块的运行机制,哪项正确?

难度: 进阶

  • A. 扩展属性会在被扩展类型中注入实例字段
  • B. 扩展成员按静态绑定规则调用,不会修改被扩展类型,也不增加其实例状态;仍可显式按静态成员形式调用
  • C. 扩展方法的优先级高于被扩展类型自身的实例方法
  • D. 扩展块必须声明在非静态类中才能访问实例状态
查看答案与解析

正确答案B

解析: 扩展成员只是一组以接收者为第一参数的静态成员,调用点在编译期静态解析:实例成员优先于扩展成员,扩展不会改变原类型布局,也不持有状态。“注入实例字段”“修改原类型”都是常见误解。

关键点: 扩展成员是静态绑定的语法糖,不改变被扩展类型。

0909 以下代码输出什么?

难度: 实战

class Order { public int Count { get; set; } }

static int SideEffect()
{
    Console.WriteLine("RHS");
    return 1;
}

Order? o = null;
o?.Count = SideEffect();
Console.WriteLine("done");
  • A. 输出 RHSdone
  • B. 编译失败,空条件访问不能作为赋值目标
  • C. 只输出 RHS
  • D. 只输出 done:接收者为 null 时整个赋值被跳过,右侧表达式不求值
查看答案与解析

正确答案D

解析: C# 14 允许 ?. 作为赋值目标(o?.Count = value)。当 o 为 null 时,整个赋值被跳过,SideEffect() 不会执行,因此只打印 done。若接收者非空,则正常求值并赋值。这一“短路到右侧不求值”的语义与 ?. 普通成员访问一致。

关键点: 空条件赋值在接收者为 null 时跳过,且不评估右侧。

0910 以下代码能否编译?

难度: 进阶

class Stats { public int Count { get; set; } }

Stats? s = null;
s?.Count++;
  • A. 编译失败 CS1059:++/-- 的操作数必须是变量、属性或索引器,空条件访问不满足
  • B. 编译通过,等价于 s?.Count += 1
  • C. 编译通过,但运行抛异常
  • D. 编译通过,s 为 null 时 Count 变为 1
查看答案与解析

正确答案A

解析: 空条件赋值支持 =、复合赋值(+=-= 等)以及事件的 +=/-=,但 ++/-- 不在支持范围:s?.Count++?. 使操作数不再是“变量、属性或索引器”,报 CS1059。需要自增时写成 s?.Count += 1

关键点: ++/-- 不适用空条件赋值,复合赋值可以。

0911 以下代码能否编译?

难度: 实战

class Notifier { public event Action? Changed; }

Notifier? n = null;
n?.Changed += () => Console.WriteLine("hi");
  • A. 编译失败,事件不能与空条件赋值连用
  • B. 编译通过,但运行抛 NullReferenceException
  • C. 编译通过:事件的 +=/-= 得到专门支持,接收者为 null 时跳过订阅
  • D. 编译通过,但事件必然被重复订阅
查看答案与解析

正确答案C

解析: 空条件赋值对事件 +=/-= 有专门支持:n?.Changed += handlern 为 null 时跳过 add/remove 操作,非 null 时正常执行。这是 C# 14 为空条件赋值列出的显式场景之一,可用于安全订阅事件。

关键点: 事件 +=/-= 是空条件赋值的受支持形态。

0912 以下代码输出什么?

难度: 实战

class Stats { public int Count { get; set; } }

Stats? s = new Stats { Count = 5 };
s?.Count -= 2;
Console.WriteLine(s!.Count);
  • A. 输出 5
  • B. 输出 3:空条件复合赋值在接收者非空时正常执行
  • C. 编译失败,复合赋值不能与 ?. 连用
  • D. 运行抛 NullReferenceException
查看答案与解析

正确答案B

解析: s?.Count -= 2 是复合赋值:先判定 s 非 null,再执行 s.Count = s.Count - 2,得到 3。复合赋值是空条件赋值支持的形态之一,接收者非空时行为与普通赋值一致。s!.Count 只是告诉编译器此处可空引用已由逻辑保证非空。

关键点: 空条件复合赋值 = 判空后执行读-改-写。

0913 以下代码能否编译?

难度: 实战

Func<int, int> f = (ref int x) => x++;
  • A. 编译通过,Func<> 支持带 ref 参数的 lambda
  • B. 编译失败,lambda 一律不允许 ref 参数
  • C. 编译通过,但运行抛异常
  • D. 编译失败 CS1677:Func<int,int> 的参数没有 ref 修饰符,签名不匹配
查看答案与解析

正确答案D

解析: C# 14 允许 lambda 参数带 ref/out/in 修饰符,但 lambda 必须与目标委托的签名一致:Func<int,int> 的参数无 ref,而 lambda 声明了 ref,报 CS1677。要使用带 ref 的 lambda,必须选择或定义签名含 ref 的委托类型。

关键点: 修饰符参与委托签名匹配,Func<>/Action<> 不带 ref

0914 以下代码输出什么?

难度: 实战

delegate void D(ref int x);

D d = (ref int x) => x++;
int n = 1;
d(ref n);
Console.WriteLine(n);
  • A. 输出 1
  • B. 输出 2,C# 14 允许 lambda 参数声明 ref/out/in
  • C. 编译失败,自定义委托也不接受 ref lambda
  • D. 输出 0
查看答案与解析

正确答案B

解析: 委托 D 的签名带 ref int,lambda (ref int x) => x++ 与之匹配,d(ref n) 通过引用自增 n,输出 2。C# 14 之前这种写法是编译错误,现在只要委托签名一致即可。

关键点: 带修饰符的 lambda 需要签名匹配的自定义委托。

0915 以下代码输出什么?

难度: 进阶

var f = (ref int x) => x++;
int n = 1;
f(ref n);
Console.WriteLine(n);
  • A. 输出 2:C# 14 下带 ref 参数的 lambda 也能推断出自然类型并用 var 接收
  • B. 编译失败,带 ref 的 lambda 必须显式写出委托类型
  • C. 输出 1
  • D. 编译失败,var 不能接收 lambda
查看答案与解析

正确答案A

解析: C# 14 的 lambda 参数修饰符特性同时支持自然类型推断:(ref int x) => x++ 可推断为“ref int 参数、int 返回”的函数类型,var f 合法,f(ref n)n 自增为 2。注意这与 0913 并不矛盾——Func<int,int> 签名不含 ref 所以不匹配,而自然类型推断完整保留了 ref 信息。

关键点: 自然类型推断保留修饰符信息,var 可以接住带 ref 的 lambda。

0916 以下代码输出什么?

难度: 进阶

delegate void DIn(in int x);

DIn d = (in int x) => Console.WriteLine(x);
int n = 5;
d(in n);
  • A. 编译失败,in 参数不能用于 lambda
  • B. 输出 0
  • C. 输出 5:in 修饰符同样受支持,且必须与委托签名一致
  • D. 运行抛 InvalidOperationException
查看答案与解析

正确答案C

解析: inref/out 一样可以在 C# 14 的 lambda 参数中声明,前提是与目标委托签名匹配。DInin intd(in n) 以只读引用传入,输出 5。in 防止被修改,但读取完全正常。

关键点: ref/out/in 三类修饰符都支持 lambda,签名必须一致。

0917 以下代码输出什么?

难度: 实战

Console.WriteLine(nameof(List<>));
Console.WriteLine(nameof(Dictionary<,>));
  • A. 编译失败,nameof 不接受开放泛型类型
  • B. 输出 ListDictionarynameof 返回类型名且不含 arity 后缀
  • C. 输出 List<>Dictionary<,>
  • D. 输出 List1Dictionary2
查看答案与解析

正确答案B

解析: C# 14 允许 nameof 作用于未绑定(开放)泛型类型:nameof(List<>) 返回 "List"nameof(Dictionary<,>) 返回 "Dictionary"nameof 产生的是编译期字符串常量,不带反引号 arity 后缀,与 typeof(...).Name 不同。

关键点: nameof(开放泛型) 返回不含 arity 的类型名。

0918 以下代码输出什么?

难度: 进阶

Console.WriteLine(nameof(List<int>));
Console.WriteLine(typeof(List<>).Name);
  • A. List<int>List
  • B. ListList
  • C. List1List1
  • D. ListList1nameof 去掉类型实参,typeofName` 含反引号与 arity
查看答案与解析

正确答案D

解析: nameof(List<int>) 只取最外层类型名,得到 "List"typeof(List<>).Name 是运行时类型元数据名称,未绑定泛型用反引号加 arity 表示,即 "List1”`。两者语义不同,最容易记混。

关键点: nameof 是编译期字符串,Type.Name 是含 arity 的运行时名称。

0919 以下代码输出什么?

难度: 进阶

class Wrapper<T> { }

Console.WriteLine(nameof(Wrapper<>));
  • A. 输出 Wrappernameof 开放泛型适用于自定义泛型类型
  • B. 编译失败,开放泛型只允许用于框架类型
  • C. 输出 Wrapper<>
  • D. 运行抛 TypeLoadException
查看答案与解析

正确答案A

解析: nameof 开放泛型不限定类型来源,自定义 Wrapper<T> 同样适用:nameof(Wrapper<>) 返回 "Wrapper"。该特性解决的是“拿不到类型实参也要取类型名”的场景,与类型是否来自框架无关。

关键点: 开放泛型 nameof 对任意泛型类型有效。

0920 关于 nameof 开放泛型与 typeof 的差异,哪项正确?

难度: 进阶

  • A. typeof(List<>) 在运行时抛异常
  • B. nameof(List<>) 返回 "List1”,与 typeof(List<>).Name` 相同
  • C. nameof 是编译期常量,nameof(List<>)nameof(List<int>) 都返回 "List"
  • D. nameof 开放泛型只能配合 #if 指令使用
查看答案与解析

正确答案C

解析: nameof 的结果是编译期字符串常量,不关心类型实参是否补齐:开放与封闭写法都返回类型名 "List"typeof(List<>) 返回未绑定 Type 对象(Name"List1”`),不抛异常。二者用途不同:前者用于标识符/日志,后者用于反射。

关键点: nameoftypeof 对泛型 arity 的处理完全不同。

官方资料

当前分类

C# 选择题

查看全部分类 →
  1. 44C# 试题 44:C# 10~12 新特性20 题
  2. 45C# 试题 45:C# 13 新特性20 题
  3. 46C# 试题 46:C# 14 新特性20 题
  4. 47C# 试题 47:unsafe 与原生互操作20 题
  5. 48C# 试题 48:装箱、闭包与性能20 题
ESC

输入关键词开始搜索