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

C# 试题 41:System.Text.Json

0801 以下代码输出什么?

难度: 实战

Console.WriteLine(JsonSerializer.Serialize(new { FirstName = "Ada", Age = 36 }));
  • A. {"FirstName":"Ada","Age":36},默认保留属性原名
  • B. {"FIRSTNAME":"ADA","AGE":36}
  • C. {"firstName":"Ada","age":36},.NET 5+ 默认命名策略为 camelCase
  • D. 抛 JsonException,匿名类型不可序列化
查看答案与解析

正确答案C

解析: 自 .NET 5 起,JsonSerializerOptions 的默认命名策略是 camelCase,序列化时属性名 FirstName/Age 会写成 firstName/age

关键点: 默认命名策略是 camelCase,不要以为默认输出 PascalCase。

0802 以下代码输出什么?

难度: 进阶

var p = JsonSerializer.Deserialize<Person>("""{"firstname":"Ada"}""");
Console.WriteLine(p?.FirstName ?? "null");

class Person { public string? FirstName { get; set; } }
  • A. 输出 null,默认反序列化大小写敏感,firstname 匹配不到 FirstName
  • B. 输出 Ada
  • C. 抛 JsonException
  • D. 编译失败
查看答案与解析

正确答案A

解析: PropertyNameCaseInsensitive 默认为 false,反序列化时 JSON 属性名与成员名做大小写敏感匹配;firstname 匹配不到 FirstName,属性保持默认值 null。camelCase 命名策略只作用于序列化写出,不改变读取匹配。

关键点: 默认读取是大小写敏感的;需要宽松匹配要显式开启选项或使用 Web 默认。

0803 以下代码输出什么?

难度: 实战

var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
var p = JsonSerializer.Deserialize<Person>("""{"firstName":"Ada"}""", options);
Console.WriteLine(p?.FirstName ?? "null");

class Person { public string? FirstName { get; set; } }
  • A. 输出 null
  • B. 输出 Ada,Web 默认开启大小写不敏感匹配并采用 camelCase
  • C. 抛 JsonException
  • D. 编译失败
查看答案与解析

正确答案B

解析: JsonSerializerDefaults.Web 组合了 camelCase 命名策略、PropertyNameCaseInsensitive = trueNumberHandling.AllowReadingFromString 等 Web 场景默认值,firstName 能匹配到 FirstName

关键点: Web 默认与 General 默认在大小写与数字处理上不同。

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

难度: 实战

var h = JsonSerializer.Deserialize<Holder>("""{"Value":"42"}""");
Console.WriteLine(h?.Value);

class Holder { public int Value { get; set; } }
  • A. 输出 42
  • B. 输出 0
  • C. 输出 null
  • D. 抛 JsonException,默认不允许从字符串读取数字
查看答案与解析

正确答案D

解析: 默认情况下 JSON 字符串 "42" 不能赋给 int 属性,需要 JsonNumberHandling.AllowReadingFromString 才会把数字字符串读入数值成员,否则抛 JsonException

关键点: 数字字符串默认读不进来,这是前后端联调常见报错源。

0805 以下代码输出什么?

难度: 实战

var p = JsonSerializer.Deserialize<Person>("""{"Name":"Ada","Extra":1}""");
Console.WriteLine(p?.Name ?? "null");

class Person { public string? Name { get; set; } }
  • A. 抛 JsonException,未知成员必须处理
  • B. 输出 Ada,默认未知成员被忽略
  • C. 输出 null
  • D. 编译失败
查看答案与解析

正确答案B

解析: 默认策略对 JSON 中多余、未映射的成员直接忽略,不报错;只有开启 UnmappedMemberHandling.Disallow 等严格选项才会抛异常。

关键点: “多出来的字段”默认静默丢弃。

0806 开启严格选项后,以下代码运行结果是什么?

难度: 进阶

var options = new JsonSerializerOptions
{
    UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow
};

var p = JsonSerializer.Deserialize<Person>("""{"Name":"Ada","Extra":1}""", options);

class Person { public string? Name { get; set; } }
  • A. 抛 JsonException,严格模式下未知成员不被允许
  • B. 正常反序列化,Extra 被忽略
  • C. 输出 null
  • D. 编译失败,该枚举不存在
查看答案与解析

正确答案A

解析: UnmappedMemberHandling.Disallow 要求 JSON 的每个属性都能映射到目标成员,出现 Extra 这样的未知成员时抛 JsonException。它常用于服务端严格校验请求体。

关键点: 严格选项把“静默忽略”变成“显式报错”。

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

难度: 实战

var n = new Node { Name = "a" };
n.Next = n;
Console.WriteLine(JsonSerializer.Serialize(n));

class Node
{
    public string? Name { get; set; }
    public Node? Next { get; set; }
}
  • A. 输出 {"Name":"a","Next":null}
  • B. 输出 {"Name":"a"}
  • C. 抛 JsonException,默认检测到对象循环引用
  • D. 无限递归直到栈溢出
查看答案与解析

正确答案C

解析: 默认情况下 System.Text.Json 检测到循环引用会抛 JsonException(“A possible object cycle was detected”),不会无限递归,也不会静默写 null。

关键点: 循环引用默认是异常,不是跳过。

0808 使用 IgnoreCycles 后,以下代码输出什么?

难度: 进阶

var options = new JsonSerializerOptions
{
    ReferenceHandler = ReferenceHandler.IgnoreCycles
};

var n = new Node { Name = "a" };
n.Next = n;
Console.WriteLine(JsonSerializer.Serialize(n, options));

class Node
{
    public string? Name { get; set; }
    public Node? Next { get; set; }
}
  • A. 抛 JsonException
  • B. 输出 {"$id":"1","Name":"a","Next":{"$ref":"1"}}
  • C. 输出 {"Name":"a"}
  • D. 输出 {"Name":"a","Next":null},循环引用位置写 null,不抛异常
查看答案与解析

正确答案D

解析: ReferenceHandler.IgnoreCycles 在遇到循环引用时把该成员写成 null 并继续,不抛异常;注意它不产生 $id/$ref 元数据,反序列化时无法还原共享引用。

关键点: IgnoreCycles 适合“只求不炸”的场景,会丢失引用信息。

0809 使用 Preserve 后,以下代码输出什么?

难度: 实战

var options = new JsonSerializerOptions
{
    ReferenceHandler = ReferenceHandler.Preserve
};

var n = new Node { Name = "a" };
n.Next = n;
Console.WriteLine(JsonSerializer.Serialize(n, options));

class Node
{
    public string? Name { get; set; }
    public Node? Next { get; set; }
}
  • A. 抛 JsonException
  • B. 输出包含 $id$ref 元数据(如 {"$id":"1","Name":"a","Next":{"$ref":"1"}}
  • C. 输出与默认选项一致
  • D. 输出 {"Name":"a","Next":null}
查看答案与解析

正确答案B

解析: ReferenceHandler.Preserve 为对象分配 $id,后续重复引用用 $ref 指向它,从而保留引用结构(包括循环与共享对象);代价是 JSON 里出现框架元数据字段。

关键点: Preserve 保留引用图,但会改变 JSON 形态。

0810 使用 ReferenceHandler.Preserve 序列化 Dictionary<int, string> 时,会发生什么?

难度: 进阶

  • A. 由于 JSON 对象键必须是字符串,非字符串键字典会序列化为 KeyValuePair 对象数组(如 [{"Key":1,"Value":"one"}]
  • B. 键自动转换为字符串,输出 {"1":"one"}
  • C. 抛 NotSupportedException
  • D. 忽略该字典
查看答案与解析

正确答案A

解析: 开启 Preserve 后,引用跟踪依赖 $id/$ref,无法与“键即字符串”的 JSON 对象形式共存,因此非字符串键字典退化为 KeyValuePair 对象数组;只有字符串键字典保持对象形态。

关键点: Preserve 会改变非字符串键字典的 JSON 结构。

0811 以下自定义转换器能否编译?

难度: 进阶

class IntToStringConverter : JsonConverter<int>
{
    public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        => reader.GetInt32();
}
  • A. 编译通过,Write 有默认实现(抛 NotSupportedException
  • B. 编译通过,序列化时自动回退默认转换器
  • C. 编译通过,序列化时忽略该转换器
  • D. 编译失败,JsonConverter<T> 的 Read 与 Write 都是抽象成员,必须全部实现
查看答案与解析

正确答案D

解析: JsonConverter<T>ReadWrite 都是抽象方法,只实现 Read 会报“未实现抽象成员”的编译错误。注意非泛型基类 JsonConverter 的 Read/Write 才是带默认实现的虚方法。

关键点: 自定义泛型转换器必须同时实现 Read 与 Write。

0812 属性上的 [JsonConverter(typeof(X))]options.Converters 注册的转换器同时存在时,哪个生效?

难度: 实战

  • A. options.Converters 总是优先
  • B. 抛 InvalidOperationException(注册冲突)
  • C. 属性上的 JsonConverterAttribute 优先于 options 注册的转换器
  • D. 由转换器类型决定,规则不确定
查看答案与解析

正确答案C

解析: 转换器选择优先级是:属性上的 [JsonConverter] > options 的 Converters 集合 > 类型上的 [JsonConverter] > 内置转换器。因此属性级标注优先。

关键点: 属性级转换器优先级最高。

0813 使用源生成 context 序列化未注册的类型,结果是什么?

难度: 进阶

var order = new Order();
Console.WriteLine(JsonSerializer.Serialize(order, typeof(Order), AppJsonContext.Default));

[JsonSerializable(typeof(Person))]
internal partial class AppJsonContext : JsonSerializerContext { }
  • A. 编译失败,Order 未注册
  • B. 运行抛 InvalidOperationException,context 中没有 Order 的元数据
  • C. 自动回退到反射序列化,正常输出
  • D. 输出空对象 {}
查看答案与解析

正确答案B

解析: 传入 JsonSerializerContext 后,序列化只使用该 context 的元数据;Order 未加 [JsonSerializable],context 查不到元数据,抛 InvalidOperationException,不会回退反射。

关键点: 源生成不会“顺带”处理未声明类型。

0814 以下代码输出什么?

难度: 实战

var p = new Person { Name = "Ada" };
Console.WriteLine(JsonSerializer.Serialize(p));

[JsonSerializable(typeof(Person))]
internal partial class AppJsonContext : JsonSerializerContext { }
  • A. 输出 {"name":"Ada"},未传 context 时走反射序列化,源生成不自动生效
  • B. 抛 InvalidOperationException,必须使用源生成
  • C. 输出 {"Name":"Ada"}
  • D. 编译失败
查看答案与解析

正确答案A

解析: 不传入 context 或 TypeInfo 时,JsonSerializer.Serialize 使用反射元数据,源生成代码不会自动接管;反射路径在普通运行时可用,但在 AOT/裁剪场景会受限。

关键点: 源生成必须显式传入 context 或 TypeInfo 才生效。

0815 开启 RespectNullableAnnotations 后,以下代码运行结果是什么?

难度: 进阶

var options = new JsonSerializerOptions { RespectNullableAnnotations = true };
var p = JsonSerializer.Deserialize<Person>("""{"Name":null}""", options);

class Person { public string Name { get; set; } = ""; }
  • A. 正常反序列化,Name 为 null
  • B. 输出空字符串
  • C. 编译失败,该选项不存在
  • D. 抛 JsonException,严格模式下 null 不能赋给非空引用类型
查看答案与解析

正确答案D

解析: RespectNullableAnnotations 开启后,反序列化器会尊重可空注解:JSON null 写入非空引用类型属性(或非空值类型)时抛 JsonException,而不是静默接受。

关键点: 严格选项把“隐式 null”变成异常,帮助提前暴露契约违例。

0816 以下代码输出什么?

难度: 实战

var p = JsonSerializer.Deserialize<Person>("""{"Name":"Ada"}""");
Console.WriteLine(p?.Name ?? "null");

class Person
{
    public string? Name { get; private set; }
}
  • A. 输出 Ada
  • B. 抛 JsonException,私有 setter 导致无法写入
  • C. 输出 null,默认反序列化不使用私有 setter
  • D. 编译失败
查看答案与解析

正确答案C

解析: 默认情况下 System.Text.Json 只使用公共 setter/init,私有 setter 不会参与反序列化,Name 保持默认值 null;需要填充非公共成员必须加 [JsonInclude]

关键点: 私有 setter 默认不写,别指望反序列化器自动绕过访问级别。

0817 以下代码输出什么?

难度: 进阶

var p = JsonSerializer.Deserialize<Point>("""{"x":1,"y":2}""");
Console.WriteLine(p?.X + "," + p?.Y);

class Point
{
    public Point(int x, int y) { X = x; Y = y; }
    public int X { get; }
    public int Y { get; }
}
  • A. 抛 JsonException,构造函数参数匹配大小写敏感
  • B. 输出 1,2,构造函数参数与 JSON 属性名的匹配大小写不敏感
  • C. 输出 0,0
  • D. 编译失败,需要 [JsonConstructor]
查看答案与解析

正确答案B

解析: 反序列化使用带参构造函数时,JSON 属性名与构造函数参数名的匹配是大小写不敏感的(与 PropertyNameCaseInsensitive 无关),x/y 都能命中参数。

关键点: 构造参数匹配与普通属性匹配的大小写规则不同。

0818 以下代码输出什么?

难度: 实战

Console.WriteLine(JsonSerializer.Serialize(new Person { FullName = "Ada" }));

class Person
{
    [JsonPropertyName("full_name")]
    public string FullName { get; set; } = "";
}
  • A. 输出 {"full_name":"Ada"},JsonPropertyName 优先于命名策略
  • B. 输出 {"fullName":"Ada"}
  • C. 输出 {"FullName":"Ada"}
  • D. 编译失败
查看答案与解析

正确答案A

解析: [JsonPropertyName] 显式指定的名称优先级高于命名策略,camelCase 不会改写它,因此输出 full_name

关键点: 显式标注压过策略;需要自定义名称时用它而不是改策略。

0819 以下代码输出什么?

难度: 进阶

Animal a = new Dog { Name = "Rex", Barks = true };
Console.WriteLine(JsonSerializer.Serialize(a));

class Animal { public string Name { get; set; } = ""; }
class Dog : Animal { public bool Barks { get; set; } }
  • A. 输出 {"Name":"Rex","Barks":true}
  • B. 输出 {"Barks":true}
  • C. 输出 {"Name":"Rex"},默认按声明类型序列化,多态需要 [JsonDerivedType]
  • D. 抛 JsonException
查看答案与解析

正确答案C

解析: 默认情况下 System.Text.Json 按声明类型(Animal)序列化,派生类属性 Barks 不会出现;要输出派生属性需要 [JsonDerivedType] 声明多态(会附带判别字段)。

关键点: 多态序列化是显式开启的,默认只输出声明类型的成员。

0820 关于 JsonSerializerOptions 的复用,哪项正确?

难度: 进阶

  • A. 每次序列化都新建 options 更安全,成本可忽略
  • B. options 在首次使用后仍可随意修改
  • C. 同一个 options 不能同时用于序列化与反序列化
  • D. 首次使用后 options 会被锁定,修改抛 InvalidOperationException;复用单例可避免反复构建内部转换器缓存
查看答案与解析

正确答案D

解析: options 首次参与序列化/反序列化后会构建内部转换器映射并进入只读状态,再修改任何属性都会抛 InvalidOperationException;每次新建也会重复构建缓存,因此应复用单例。

关键点: 把 options 当作“配置一次、全局复用”的不可变对象。

官方资料

当前分类

C# 选择题

查看全部分类 →
  1. 39C# 试题 39:反射与特性20 题
  2. 40C# 试题 40:dynamic 与表达式树20 题
  3. 41C# 试题 41:System.Text.Json20 题
  4. 42C# 试题 42:HttpClient 与网络基础20 题
  5. 43C# 试题 43:比较、格式化与解析20 题
ESC

输入关键词开始搜索