You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
    }
}

关键说明

  1. 自动收集预定义对象Key:静态构造函数会扫描所有已加载程序集中的公开静态Test实例,自动将它们的Key加入全局集合,无需手动维护映射,也支持跨程序集定义预定义对象。
  2. 构造函数分离逻辑:
    • 公开构造函数保留Key唯一性检查,确保用户手动创建的实例不会重复
    • 带[JsonConstructor]标记的私有构造函数专供反序列化使用,跳过检查,避免反序列化时抛出异常
  3. 兼容特殊场景:反射等方式可以通过调用私有构造函数创建实例,不受Key唯一性限制,符合需求要求。

内容的提问来源于stack exchange,提问作者user246392

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 20:05:53