C#预定义唯一Key静态对象反序列化冲突问题求解
解决C#预定义对象Key唯一性与反序列化冲突问题
需求回顾
需要实现:
- 包含唯一标识
Key属性的类 - 一组预定义静态对象
- 仅限制用户手动创建的实例Key唯一,反序列化、反射等场景无需限制
- 无需手动维护Key映射,支持跨程序集定义预定义对象
问题根源
原代码中构造函数对所有实例化操作(包括反序列化)都执行Key唯一性检查,导致反序列化已存在Key的对象时抛出异常。
解决方案代码
using System; using System.Collections.Generic; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; public sealed class Test { private static readonly HashSet<string> _existingKeys = []; // 预定义静态对象示例 public static readonly Test One = new("one"); public static readonly Test Two = new("two"); // 静态构造函数:自动扫描所有程序集中的静态Test实例,收集Key static Test() { foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { foreach (var type in assembly.GetTypes()) { foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static)) { if (field.FieldType == typeof(Test) && field.GetValue(null) is Test instance) { _existingKeys.Add(instance.Key); } } } } } // 公开构造函数:供用户手动创建实例,强制执行Key唯一性检查 public Test(string key) { if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key)); if (!_existingKeys.Add(key)) { throw new ArgumentException($"Key '{key}' is already in use."); } Key = key; } // 私有构造函数:标记为Json构造函数,供反序列化使用,跳过Key检查 [JsonConstructor] private Test(string key, bool skipKeyCheck) { Key = key ?? throw new ArgumentNullException(nameof(key)); } public string Key { get; } } // 测试代码 class Program { static void Main() { // 测试用户手动创建重复Key:触发异常 try { var duplicate = new Test("one"); } catch (ArgumentException ex) { Console.WriteLine(ex.Message); // 输出: Key 'one' is already in use. } // 测试序列化与反序列化:正常执行 var serialized = JsonSerializer.Serialize(Test.One); var deserialized = JsonSerializer.Deserialize<Test>(serialized); Console.WriteLine($"反序列化结果Key: {deserialized.Key}"); // 输出: 反序列化结果Key: one // 测试反射创建实例:跳过Key检查 var constructor = typeof(Test).GetConstructor( BindingFlags.NonPublic | BindingFlags.Instance, new[] { typeof(string), typeof(bool) }); var reflectedInstance = constructor?.Invoke(new object[] { "reflection-key", true }) as Test; Console.WriteLine($"反射实例Key: {reflectedInstance?.Key}"); // 输出: 反射实例Key: reflection-key } }
关键说明
- 自动收集预定义对象Key:静态构造函数会扫描所有已加载程序集中的公开静态
Test实例,自动将它们的Key加入全局集合,无需手动维护映射,也支持跨程序集定义预定义对象。 - 构造函数分离逻辑:
- 公开构造函数保留Key唯一性检查,确保用户手动创建的实例不会重复
- 带
[JsonConstructor]标记的私有构造函数专供反序列化使用,跳过检查,避免反序列化时抛出异常
- 兼容特殊场景:反射等方式可以通过调用私有构造函数创建实例,不受Key唯一性限制,符合需求要求。
内容的提问来源于stack exchange,提问作者user246392
相关产品推荐
相关产品推荐

