C# 试题 04:运算符与表达式
0061 以下代码输出什么?
难度: 实战
int x = 1;
x = x++;
Console.WriteLine(x);
- A.
2 - B.
1,后置自增返回旧值,赋值把自增结果覆盖掉 - C.
0 - D. 编译失败
查看答案与解析
正确答案B
解析: x++ 先返回旧值 1 再自增(此时 x 为 2),随后赋值把 2 覆盖回 1,最终 x 是 1。
关键点: x = x++ 是经典陷阱,结果不是 2。
0062 以下代码输出什么?
难度: 实战
int i = 0;
int r = i++ + ++i;
Console.WriteLine(r);
- A.
1 - B.
2(先求值左操作数i++(旧值 0,i变 1),再求值右操作数++i(i变 2),结果为 0 + 2) - C.
3 - D. 编译失败
查看答案与解析
正确答案B
解析: 操作数从左到右求值:左 i++ 得 0(i=1),右 ++i 得 2(i=2),0 + 2 = 2。
关键点: 自增副作用发生在各自操作数求值时刻,不要按“先算完整表达式”理解。
0063 以下代码输出什么?
难度: 实战
static int A() { Console.Write("A"); return 1; }
static int B() { Console.Write("B"); return 2; }
Console.Write(A() + B() * 3);
- A.
BA7 - B.
AB9 - C.
AB7(乘法优先级只决定运算结合,操作数仍从左到右求值) - D.
BA9
查看答案与解析
正确答案C
解析: 优先级决定的是“谁先算”,不是“谁先求值”:A() 先求值打印 A,再求值 B() 打印 B,最后 1 + 2*3 = 7,输出 AB7。
关键点: 优先级 ≠ 求值顺序;副作用顺序按操作数从左到右。
0064 以下代码输出什么?
难度: 实战
int[] arr = { 1, 2 };
int index = 0;
arr[index++] += 10;
Console.WriteLine(arr[0] + "," + arr[1] + "," + index);
- A.
11,2,1(复合赋值中索引表达式只求值一次) - B.
11,2,0 - C.
1,12,1 - D.
12,2,1
查看答案与解析
正确答案A
解析: arr[index++] += 10 中索引 index++ 只求值一次:目标为 arr[0],index 变为 1,arr[0] = 1 + 10 = 11。
关键点: 复合赋值不会“两次取索引”,这既是优点也是容易误判的点。
0065 以下代码输出什么?
难度: 进阶
static bool F() { Console.Write("F"); return false; }
static bool T() { Console.Write("T"); return true; }
Console.WriteLine(F() && T());
Console.WriteLine(T() || F());
- A. 第一行
FFalse,第二行TTrue(&&/||短路,右侧不再求值) - B. 两行都执行所有调用
- C. 第一行
FFalse,第二行TFTTrue - D. 编译失败
查看答案与解析
正确答案A
解析: && 左侧为 false 时不求值右侧;|| 左侧为 true 时不求值右侧。F() 打印 F 后返回 false,WriteLine(false) 打印 False。
关键点: 把有副作用的调用放在 &&/|| 右侧,可能永远不会执行。
0066 以下代码输出什么?
难度: 实战
int x = 1;
Console.WriteLine(x << 31);
Console.WriteLine(x << 32);
- A.
-2147483648和0 - B.
2147483647和1 - C. 编译失败
- D.
-2147483648和1(int移位计数按 32 取模,1 << 32等价于1 << 0)
查看答案与解析
正确答案D
解析: int 移位时移位计数对 32 取模:1 << 31 把符号位置 1,得 int.MinValue;1 << 32 等价 1 << 0,得 1。
关键点: 超出位宽的移位不会置零,而是取模,容易导致诡异结果。
0067 以下代码输出什么?
难度: 进阶
string a = "hello";
string b = "hello";
string c = new string("hello".ToCharArray());
Console.WriteLine(a == b);
Console.WriteLine(a == c);
Console.WriteLine(ReferenceEquals(a, c));
- A.
True、False、False - B.
True、True、False(string的==是值比较,ReferenceEquals是引用比较) - C.
True、True、True - D.
False、True、False
查看答案与解析
正确答案B
解析: string 重载了 ==,比较内容是否相等;ReferenceEquals 比较引用,new string(...) 创建了新对象,与常量引用不同。
关键点: 字符串的 == 是值语义,但跨 object 引用比较时可能意外。
0068 以下代码输出什么?
难度: 实战
object a = "ab";
object b = "a" + "b";
Console.WriteLine(a == b);
- A.
True,两者引用同一个驻留字符串(编译期常量拼接的结果也是 interned) - B.
False,object的==比较引用且字符串内容不同 - C.
False,运行时拼接产生新对象 - D. 编译失败
查看答案与解析
正确答案A
解析: "a" + "b" 是编译期常量表达式,结果 "ab" 与字面量一样被驻留,a、b 引用同一对象;object 的 == 是引用比较,因此为 True。
关键点: 依赖字符串驻留写业务判断很危险,应改用 Equals/StringComparison。
0069 以下代码输出什么?
难度: 实战
object o = "text";
Console.WriteLine(o as string);
Console.WriteLine(o as int?);
- A. 两行都输出
text - B. 第二行抛
InvalidCastException - C. 两行都输出空行
- D. 第一行输出
text,第二行输出空行(as失败得到null,不抛异常)
查看答案与解析
正确答案D
解析: as 只用于引用类型和可空值类型,失败时返回 null;"text" 不是 int,o as int? 为 null,WriteLine(null) 输出空行。
关键点: as 失败是 null 而不是异常;对不可空值类型不能使用 as。
0070 以下代码输出什么?
难度: 进阶
Console.WriteLine(nameof(List<int>));
Console.WriteLine(nameof(int.MaxValue));
- A.
List<int>和MaxValue - B.
List和MaxValue(nameof省略泛型实参,返回成员名) - C.
List和int.MaxValue - D. 编译失败
查看答案与解析
正确答案B
解析: nameof 返回标识符的名字:泛型类型只保留类型名(去掉类型参数),成员返回成员名(去掉类型前缀),所以是 List 和 MaxValue。
关键点: nameof 常用于反射/日志键,输出形式与直觉可能不同。
0071 以下代码输出什么?
难度: 进阶
int x = 1 + 2 << 3;
Console.WriteLine(x);
- A.
9 - B.
33 - C.
24(加法优先级高于移位,等价于(1 + 2) << 3) - D.
16
查看答案与解析
正确答案C
解析: 优先级从高到低:加减高于移位,1 + 2 << 3 解析为 (1 + 2) << 3 = 3 << 3 = 24。
关键点: 混淆移位与算术优先级是经典低级错误,可读性优先用括号。
0072 以下代码输出什么?
难度: 实战
int[] arr = { 10, 20 };
int i = 0;
arr[i] = arr[++i];
Console.WriteLine(arr[0] + "," + arr[1] + "," + i);
- A.
10,20,1 - B.
20,10,1 - C.
20,20,0 - D.
20,20,1(先确定赋值目标arr[0],再求值右侧arr[++i])
查看答案与解析
正确答案D
解析: 赋值表达式的左操作数先求值:目标确定是 arr[0](此时 i=0),再求右侧 arr[++i](i 变 1,值 20),最后 arr[0] = 20。
关键点: 赋值目标在右侧求值之前就被锁定,i 的副作用不会改目标。
0073 关于循环中用 string += 拼接,哪项正确?
难度: 实战
- A. 每次迭代原地修改,成本 O(1)
- B. 每次迭代创建一个新字符串,累计复制成本约 O(n²),应优先使用
StringBuilder - C. 编译器自动优化为
StringBuilder - D. 字符串超过一定长度后自动改用
StringBuilder
查看答案与解析
正确答案B
解析: string 不可变,+= 每次分配新对象并复制原内容,n 次拼接累计 O(n²);StringBuilder 用可变缓冲区把成本降到接近 O(n)。
关键点: 编译器的拼接优化只对常量/少量拼接有效,不适用于循环内动态拼接。
0074 以下代码输出什么?
难度: 进阶
object a = 5;
object b = 5;
Console.WriteLine(a == b);
Console.WriteLine(a.Equals(b));
- A.
False和True(object的==是引用比较;Equals走运行时值比较) - B.
True和True - C.
False和False - D.
True和False
查看答案与解析
正确答案A
解析: 两个装箱后的 int 是不同对象,object 的 == 比较引用为 False;Equals 是虚方法,Int32.Equals 按值比较为 True。
关键点: 装箱后忘记值语义是高频 Bug 来源。
0075 关于运算符重载,哪项正确?
难度: 进阶
- A. 可以重载
&&、||、?: - B. 可以重载赋值运算符
= - C. 可以重载
+、-、*、==等,但不能重载&&、||、?:、is、as、=;短路运算符通过重载&/|和true/false间接支持 - D. 只能重载
==和!=
查看答案与解析
正确答案C
解析: 可重载运算符是有明确清单的(算术、比较、移位等);&&/|| 不能直接重载,但重载 &/| 与 true/false 后编译器会合成短路版本;=、?:、is、as、?. 等不可重载。
关键点: “能重载什么”是面试常考点,不要凭感觉。
0076 以下代码输出什么?
难度: 实战
static string Describe(object? o) => o switch
{
int > 100 => "big",
int => "small",
null => "none",
_ => "other"
};
Console.WriteLine(Describe(50));
Console.WriteLine(Describe(null));
Console.WriteLine(Describe("x"));
- A.
small、other、other - B.
small、none、other(switch 表达式按分支顺序匹配,int > 100不命中再落int) - C.
big、none、other - D. 编译失败
查看答案与解析
正确答案B
解析: 开关表达式自上而下匹配:50 不满足 int > 100,命中 int;null 命中 null 分支;"x" 落到 _。分支顺序决定结果。
关键点: 更具体的模式(关系/类型)要放在一般模式之前。
0077 以下代码输出什么?
难度: 进阶
static int? Get() { Console.Write("G"); return null; }
var r = Get() ?? Get() ?? 1;
Console.WriteLine(r);
- A.
G和1 - B.
GGG和1 - C.
GG和1(??从左到右短路,左侧非null就不再求值右侧) - D. 编译失败
查看答案与解析
正确答案C
解析: ?? 左结合、逐个短路:第一次 Get() 得 null,再调第二次 Get() 得 null,最后取 1;Get 被调用两次,输出 GG 和 1。
关键点: 链式 ?? 不是“全部求值再选”,是逐个短路。
0078 关于字符串比较,哪项正确?
难度: 进阶
- A.
==与string.Equals(string)默认都是区分大小写的序号比较;需要文化规则或忽略大小写时应显式传StringComparison - B.
==是引用比较 - C.
Equals总是忽略大小写 - D. 默认比较会忽略大小写
查看答案与解析
正确答案A
解析: string 的 == 和 Equals(string) 默认使用 StringComparison.Ordinal(区分大小写);要忽略大小写或按文化比较,必须显式指定比较方式。
关键点: 字符串比较“默认区分大小写”是常见认知缺口。
0079 以下代码输出什么?
难度: 实战
class Counter
{
private int _v;
public int V
{
get { Console.Write("G"); return _v; }
set { Console.Write("S"); _v = value; }
}
}
var c = new Counter();
c.V += 1;
Console.Write(c.V);
- A.
GSG1(复合赋值先读一次 getter,再写一次 setter,随后读取再触发 getter) - B.
GS1 - C.
G1 - D.
GG1
查看答案与解析
正确答案A
解析: c.V += 1 展开为“读一次 getter(G)+ 算 + 写一次 setter(S)”;随后 Console.Write(c.V) 再读一次 getter(G)并输出 1,合计 GSG1。
关键点: 复合赋值对属性只读一次、只写一次,但后续访问会再次触发 getter。
0080 以下代码输出什么?
难度: 实战
int x = 3;
x *= 2 + 3;
Console.WriteLine(x);
- A.
9 - B.
11 - C. 编译失败
- D.
15(复合赋值等价于x = x * (2 + 3),右侧整体作为乘法因子)
查看答案与解析
正确答案D
解析: 复合赋值 x *= 2 + 3 等价于 x = x * (2 + 3),右侧表达式整体参与运算,3 * 5 = 15;不是 x * 2 + 3。
关键点: 复合赋值的右侧是“完整表达式”,优先级陷阱常在这里出现。