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

C# 试题 43:比较、格式化与解析

0841 以下代码输出什么?

难度: 实战

var list = new List<Point> { new Point { X = 1 } };
Console.WriteLine(list.Contains(new Point { X = 1 }));

struct Point : IEquatable<Point>
{
    public int X;
    public bool Equals(Point other) => X == other.X;
}
  • A. 编译失败,struct 不能实现 IEquatable
  • B. 输出 False
  • C. 输出 TrueList<T>.Contains 通过 EqualityComparer<T>.Default 调用 IEquatable<T>.Equals
  • D. 抛 InvalidOperationException
查看答案与解析

正确答案C

解析: EqualityComparer<T>.Default 在 T 实现 IEquatable<T> 时优先使用它,List<T>.Contains 因此走 Point.Equals(Point),对值类型无需装箱,两个 X=1 的 Point 相等,输出 True。

关键点: 泛型容器默认比较优先走 IEquatable<T>

0842 以下代码输出什么?

难度: 进阶

var a = new Person { Name = "Ada" };
var b = new Person { Name = "Ada" };
var list = new List<Person> { a };

Console.WriteLine(list.Contains(b));
Console.WriteLine(ReferenceEquals(a, b));

class Person : IEquatable<Person>
{
    public string Name = "";
    public bool Equals(Person? other) => other is not null && Name == other.Name;
}
  • A. 输出 TrueFalse,Contains 走 IEquatable<T>,而引用比较仍基于 ReferenceEquals
  • B. 输出 FalseFalse
  • C. 输出 TrueTrue
  • D. 编译失败,未重写 Equals(object)
查看答案与解析

正确答案A

解析: 类实现 IEquatable<T> 后,EqualityComparer<T>.Default 在 Contains 中调用它,因此两个 Name 相同的实例相等;但 ReferenceEquals 依然为 False。若同时用到 HashSet/Dictionary,还必须重写 GetHashCode,否则哈希结构行为错乱。

关键点: IEquatable<T> 与引用比较可以并存且结论不同。

0843 以下代码输出什么?

难度: 进阶

var a = new Person { Name = "Ada" };
var b = new Person { Name = "Ada" };
Console.WriteLine(a == b);

class Person : IEquatable<Person>
{
    public string Name = "";
    public bool Equals(Person? other) => other is not null && Name == other.Name;
}
  • A. 输出 True,IEquatable 让 == 生效
  • B. 输出 True,字符串相同所以 == 为 true
  • C. 编译失败
  • D. 输出 False,== 默认做引用比较,实现 IEquatable<T> 不会自动重载 ==
查看答案与解析

正确答案D

解析: IEquatable<T>Equals(object)operator == 是三个独立的契约:只实现 IEquatable 不会自动生成 ==,自定义类型默认的 == 是引用相等,因此两个不同实例比较为 False。

关键点: 需要 == 必须显式重载,IEquatable 不会代劳。

0844 以下代码输出什么?

难度: 进阶

string a = "a";
string? b = null;

Console.WriteLine(a.CompareTo(b));
Console.WriteLine(b.CompareTo(a));
  • A. 输出 1-1
  • B. 输出 1,然后抛 NullReferenceException;任意非 null 实例与 null 比较时大于 null,而 null 上调用实例方法抛 NRE
  • C. 输出 00
  • D. 抛 ArgumentNullException
查看答案与解析

正确答案B

解析: IComparable<T>.CompareTo 的契约规定“任意非 null 实例大于 null”,所以 a.CompareTo(null) 返回 1;但 b 本身是 null,调用其实例方法 CompareTo 时抛 NullReferenceException

关键点: “与 null 比较”和“在 null 上调用”是两种完全不同的结果。

0845 以下代码输出什么?

难度: 实战

var items = new List<(int K, string V)> { (1, "a"), (1, "b"), (0, "c") };
items.Sort((x, y) => x.K.CompareTo(y.K));
Console.WriteLine(string.Join(",", items.Select(i => i.V)));
  • A. 一定是 c,a,b
  • B. 一定是 c,b,a
  • C. 可能是 c,a,bc,b,aList<T>.Sort 不保证稳定排序
  • D. 编译失败
查看答案与解析

正确答案C

解析: List<T>.Sort 使用不稳定的排序算法,键相同时(两个 K=1)元素的相对顺序不保证;需要稳定排序应使用 LINQ 的 OrderBy(稳定排序)。

关键点: Sort 不稳定、OrderBy 稳定,需要保持原顺序时别用 Sort。

0846 以下代码输出什么?

难度: 实战

var items = new List<Item> { new Item { V = 2 }, new Item { V = 1 } };
items.Sort();
Console.WriteLine(items[0].V);

class Item : IComparable<Item>
{
    public int V;
    public int CompareTo(Item? other) => other is null ? 1 : V.CompareTo(other.V);
}
  • A. 输出 1,Sort 默认使用 Comparer<T>.Default,走 IComparable<T>
  • B. 输出 2
  • C. 抛 ArgumentException
  • D. 编译失败
查看答案与解析

正确答案A

解析: List<T>.Sort() 默认比较器是 Comparer<T>.Default,它优先使用 IComparable<T>.CompareTo,因此按 V 升序排列后第一项是 V=1。

关键点: 排序默认走 IComparable<T>,而不是 Equals。

0847 以下代码输出什么?

难度: 进阶

var list = new List<Item> { new Item { V = 1 }, new Item { V = 2 }, new Item { V = 3 } };
Console.WriteLine(list.BinarySearch(new Item { V = 2 }) >= 0);

class Item : IComparable<Item>
{
    public int V;
    public int CompareTo(Item? other) => other is null ? 1 : V.CompareTo(other.V);
    public override bool Equals(object? obj) => false;
    public override int GetHashCode() => V;
}
  • A. 输出 False,Equals 不一致导致找不到
  • B. 抛 InvalidOperationException
  • C. 编译失败
  • D. 输出 True,BinarySearch 只依赖比较器(CompareTo),不调用 Equals
查看答案与解析

正确答案D

解析: List<T>.BinarySearch 只使用 Comparer<T>.Default(即 CompareTo)做比较,从不调用 Equals;即使 Equals 恒为 false,只要 CompareTo 一致就能命中。反过来也说明:CompareTo 与 Equals 不一致会让排序/查找与哈希结构的语义分裂。

关键点: BinarySearch 与 Equals 无关,契约一致性要自己保证。

0848 以下代码输出什么?

难度: 实战

bool ok = int.TryParse("0x1F", out int n);
Console.WriteLine(ok + " " + n);
  • A. 输出 True 31
  • B. 输出 False 0,默认 NumberStyles.Integer 不含 AllowHexSpecifier
  • C. 输出 False 31
  • D. 抛 FormatException
查看答案与解析

正确答案B

解析: int.TryParse 默认使用 NumberStyles.Integer,它不允许 0x 前缀,解析失败返回 false,out 参数置为 0。要解析十六进制必须显式传入 NumberStyles.HexNumberAllowHexSpecifier

关键点: 十六进制不是默认行为,别指望 TryParse 自动识别 0x。

0849 以下代码输出什么?

难度: 进阶

var de = CultureInfo.GetCultureInfo("de-DE");

Console.WriteLine(decimal.Parse("1,5", NumberStyles.Float, de));
Console.WriteLine(decimal.Parse("1.5", NumberStyles.Float, de));
  • A. 两行都输出 1.5
  • B. 输出 1.515
  • C. 输出 1.5,然后抛 FormatException;de-DE 的小数分隔符是逗号,点号不是合法小数符号
  • D. 两行都抛 FormatException
查看答案与解析

正确答案C

解析: 解析必须使用当前文化的符号表:de-DE 的小数分隔符是 ,,第一行成功得到 1.5;第二行的 . 在 de-DE 是千分位分隔符,而 NumberStyles.Float 不含 AllowThousands,故抛 FormatException

关键点: 解析数字必须显式指定或确认文化,跨文化解析是最常见的隐晦 bug。

0850 以下代码输出什么?

难度: 实战

try
{
    int.Parse("12x");
}
catch (Exception ex)
{
    Console.WriteLine(ex.GetType().Name);
}
Console.WriteLine(int.TryParse("12x", out _));
  • A. 输出 FormatExceptionFalse,同一输入 Parse 抛异常而 TryParse 返回 false
  • B. 输出 FormatExceptionTrue
  • C. 输出 OverflowExceptionFalse
  • D. 输出 ArgumentNullExceptionFalse
查看答案与解析

正确答案A

解析: Parse 失败抛异常,TryParse 失败只返回 false 不抛异常,这是两者最核心的契约差异;非法格式抛 FormatException,超出范围才抛 OverflowException

关键点: Parse 用异常表达失败,TryParse 用返回值表达失败。

0851 对 int 值做字符串插值 $"{value}" 时,编译器生成的 DefaultInterpolatedStringHandler 通过哪个接口避免中间字符串分配?

难度: 进阶

  • A. IFormattable.ToString
  • B. object.ToString
  • C. Convert.ToString
  • D. ISpanFormattable.TryFormat
查看答案与解析

正确答案D

解析: 插值处理程序优先调用 ISpanFormattable.TryFormat 把值直接格式化进目标缓冲区(Span),避免先 ToString 产生中间字符串再复制。这正是值类型实现 ISpanFormattable 的收益。

关键点: 高性能格式化路径走 TryFormat,不走 ToString。

0852 以下代码输出什么?

难度: 实战

var buffer = new char[2];
bool ok = 12345.TryFormat(buffer, out int written);
Console.WriteLine(ok + " " + written);
  • A. 输出 True 2
  • B. 输出 False 0,缓冲区不足时 TryFormat 返回 false 且 charsWritten 置 0,而不是抛异常
  • C. 输出 False 5
  • D. 抛 ArgumentException
查看答案与解析

正确答案B

解析: ISpanFormattable.TryFormat 的契约是:目标缓冲区放不下时返回 false 并把 charsWritten 置 0,由调用方扩容后重试;12345 需要 5 个字符,2 个字符的缓冲区放不下。

关键点: TryFormat 用返回值表达“缓冲区不够”,不抛异常。

0853 以下代码输出什么?

难度: 进阶

var utf8 = new byte[16];
bool ok = 12345.TryFormat(utf8, out int bytesWritten);
Console.WriteLine(ok + " " + bytesWritten);
  • A. 输出 True 10,每个数字占 2 字节
  • B. 输出 False 0,byte 重载不存在
  • C. 输出 True 5,.NET 8+ 提供 byte(UTF-8)TryFormat 重载,每个 ASCII 数字占 1 字节
  • D. 编译失败
查看答案与解析

正确答案C

解析: 自 .NET 8 起数值类型提供 TryFormat(Span<byte>, out int, ...) 的 UTF-8 重载,直接把数字写成 UTF-8 字节;12345 是 5 个 ASCII 字符,占 5 字节,输出 True 5。

关键点: char 版本的计数单位是字符,byte 版本是字节。

0854 以下代码输出什么?

难度: 实战

var buffer = new char[8];
bool ok = 255.TryFormat(buffer, out int written, "X");
Console.WriteLine(ok + " " + buffer[..written].ToString());
  • A. 输出 True FF,格式说明符 X 生成大写十六进制
  • B. 输出 True 255
  • C. 输出 False 0
  • D. 编译失败,TryFormat 不支持格式说明符
查看答案与解析

正确答案A

解析: TryFormat 的第三个参数是格式说明符,与 ToString("X") 一致:255 用 X 格式化为大写十六进制 FF,8 个字符的缓冲区足够。

关键点: TryFormat 支持格式说明符,机制与 ToString 相同。

0855 以下代码输出什么?

难度: 实战

var style = NumberStyles.Integer | NumberStyles.AllowThousands;
bool ok = int.TryParse("1,000", style, CultureInfo.InvariantCulture, out int n);
Console.WriteLine(ok + " " + n);
  • A. 输出 False 0
  • B. 输出 True 1
  • C. 抛 FormatException
  • D. 输出 True 1000,AllowThousands 允许千分位分隔符
查看答案与解析

正确答案D

解析: 默认的 NumberStyles.Integer 不含 AllowThousands,"1,000" 解析失败;加上该标志并在 InvariantCulture(逗号是千分位符)下解析,得到 1000。

关键点: 千分位是显式开启的样式,不是默认能力。

0856 关于 Dictionary 与 SortedDictionary 的键判定,哪项正确?

难度: 进阶

  • A. 两者都用 Equals 判断键
  • B. Dictionary 用 GetHashCode+Equals(默认走 IEquatable<T>),有序集合用 Comparer<T>.Default(走 IComparable<T>),两者的“相等”标准可以不同
  • C. 两者都用 CompareTo
  • D. 两者都要求键实现 IComparable
查看答案与解析

正确答案B

解析: Dictionary/HashSet 的键判定基于哈希与相等性(默认 EqualityComparer<T>.DefaultIEquatable<T>);SortedDictionary/SortedSet 基于排序(Comparer<T>.DefaultIComparable<T>)。两个“相等”标准在实现不一致时会得出不同结论。

关键点: 无序集合与有序集合对“同一个键”的判定标准不同。

0857 以下代码输出什么?

难度: 进阶

double nan = double.NaN;

Console.WriteLine(nan.CompareTo(1.0));
Console.WriteLine(nan < 1.0);
  • A. 输出 1True
  • B. 输出 0False
  • C. 输出 -1False,IComparable 把 NaN 视为小于任何值,而 IEEE 比较运算符对 NaN 恒为 false
  • D. 输出 -1True
查看答案与解析

正确答案C

解析: Double.CompareTo 遵循 IComparable 契约:NaN 小于任何非 NaN 值(包括与自身比较为 0),所以返回 -1;而 < 等 IEEE 754 运算符对 NaN 的任何比较都为 false。同一数值在两条路径下语义相反。

关键点: CompareTo 与比较运算符对 NaN 的语义不同,排序 NaN 前要先定好规则。

0858 以下代码输出什么?

难度: 实战

string a = "a";
string b = "A";

Console.WriteLine(a == b);
Console.WriteLine(string.Compare(a, b, StringComparison.Ordinal));
  • A. 输出 False1,== 是大小写敏感的序数比较,Ordinal 下 ‘a’(97) 大于 ‘A’(65)
  • B. 输出 True0
  • C. 输出 False-1
  • D. 输出 True1
查看答案与解析

正确答案A

解析: string == 做的是大小写敏感的序数相等比较,"a" != "A"Compare 按 Ordinal 比较码点,'a'(0x61) 大于 'A'(0x41),返回正数 1。很多人凭直觉以为小写“应该排在前面”而猜 -1。

关键点: Ordinal 比较按码点大小,‘a’ > ‘A’。

0859 以下代码输出什么?

难度: 进阶

static void Write<T>(T value) where T : ISpanFormattable
{
    var buffer = new char[32];
    bool ok = value.TryFormat(buffer, out int written, default, null);
    Console.WriteLine(ok + " " + written);
}

Write(12345);
  • A. 编译失败,ISpanFormattable 不能作为泛型约束
  • B. 输出 True 10
  • C. 输出 False 0
  • D. 输出 True 5,泛型约束下值类型以受限调用调用 TryFormat,不装箱
查看答案与解析

正确答案D

解析: where T : ISpanFormattable 让编译器用受限调用(constrained call)直接调用值类型的 TryFormat,不装箱;12345 格式化 5 个字符,输出 True 5。若不加约束而把值转成接口引用,就会装箱并可能退化为 ToString 路径。

关键点: 泛型约束是避免值类型装箱调用接口方法的关键。

0860 自定义值类型实现 ISpanFormattable 而非只重写 ToString,主要收益是什么?

难度: 进阶

  • A. 没有任何收益,只是多实现一个接口
  • B. 插值、拼接与 UTF-8 格式化路径可以复用 TryFormat,避免中间字符串分配与复制
  • C. 让类型支持 JSON 序列化
  • D. 让类型可以放进 Dictionary
查看答案与解析

正确答案B

解析: 实现 ISpanFormattable.TryFormat 后,字符串插值、StringBuilder.Append 的 span 路径以及 UTF-8 格式化都能直接写入目标缓冲区,省去 ToString 的中间字符串分配;这在高频格式化场景收益明显。

关键点: TryFormat 是“零分配格式化”的入口。

官方资料

当前分类

C# 选择题

查看全部分类 →
  1. 41C# 试题 41:System.Text.Json20 题
  2. 42C# 试题 42:HttpClient 与网络基础20 题
  3. 43C# 试题 43:比较、格式化与解析20 题
  4. 44C# 试题 44:C# 10~12 新特性20 题
  5. 45C# 试题 45:C# 13 新特性20 题
ESC

输入关键词开始搜索