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

如何用Json.NET将十六进制键的JSON字典反序列化为Dictionary<uint, T>

如何将JSON中十六进制键的字典反序列化为Dictionary<uint, T>

问题场景

我有一个包含特殊字典结构的复杂JSON对象,示例结构如下:

{
  ...
  "SomeDictionary": {
    "0x010": {
      "a": "b"
    },
    "0x020": {
      "a": "b"
    },
    "0x030": {
      "a": "b"
    }
  }
  ...
}

需要将其中键为十六进制字符串(格式为0xXXX)的字典反序列化为.NET中的Dictionary<uint, T>类型(T为字典值的具体类型)。

已排除的方案

  • 为每个目标字典单独创建转换器:存在多个此类字典,不想重复定义转换器(即使泛型实现也不愿采用)
  • 使用类型转换器:不想将字典键包装到自定义类中

当前采用的可行方案

通过DTO中转实现转换:

  1. 定义包含Dictionary<string, MyType>的DTO类:
public record class ComplexObjectDTO(
    // 其他属性
    Dictionary<string, MyType> SomeDictionary
    // 其他属性
);
  1. 反序列化到DTO后,通过辅助函数转换为领域对象的Dictionary<uint, T>:
private static Dictionary<uint, T> ToUintDictionary<T>(Dictionary<string, T> source) =>
    source.ToDictionary(
        x =>
        {
            var str = x.Key;
            if (!str.StartsWith("0x"))
                throw new Exception($"Expected hexadecimal number, got {str} instead");
            return Convert.ToUInt32(str, 16);
        },
        x => x.Value
    );

该方案因本身需要使用DTO而可行,但希望找到更直接的替代方案。

替代解决方案

方案1:全局契约解析器(推荐)

自定义契约解析器,自动处理所有Dictionary<uint, T>类型的键序列化/反序列化,无需为每个字典单独配置:

public class UIntKeyContractResolver : DefaultContractResolver
{
    protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
    {
        var contract = base.CreateDictionaryContract(objectType);
        // 仅处理键类型为uint的字典
        if (objectType.GetGenericArguments()[0] == typeof(uint))
        {
            // 序列化时将uint键转为0x开头的十六进制字符串
            contract.DictionaryKeyResolver = key =>
            {
                if (key is uint uintKey)
                    return $"0x{uintKey:X}";
                return key.ToString();
            };
            // 反序列化时将0x开头的字符串键转为uint
            contract.DictionaryKeyDeserializer = (reader, keyType) =>
            {
                if (reader.TokenType != JsonToken.PropertyName)
                    throw new JsonSerializationException("Expected property name");

                var keyStr = reader.Value.ToString();
                if (!keyStr.StartsWith("0x"))
                    throw new JsonSerializationException($"Expected hexadecimal key, got {keyStr} instead");

                if (!uint.TryParse(keyStr.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var uintKey))
                    throw new JsonSerializationException($"Invalid hexadecimal key: {keyStr}");

                return uintKey;
            };
        }
        return contract;
    }
}

使用方式:
在反序列化时指定契约解析器,所有Dictionary<uint, T>属性都会自动适配:

var settings = new JsonSerializerSettings
{
    ContractResolver = new UIntKeyContractResolver()
};
var domainObject = JsonConvert.DeserializeObject<ComplexDomainObject>(jsonString, settings);

方案2:通用泛型字典转换器

创建针对Dictionary<uint, T>的泛型转换器,可全局注册或按需标记属性:

public class UIntKeyDictionaryConverter<T> : JsonConverter<Dictionary<uint, T>>
{
    public override Dictionary<uint, T> ReadJson(JsonReader reader, Type objectType, Dictionary<uint, T> existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var result = new Dictionary<uint, T>();
        if (reader.TokenType != JsonToken.StartObject)
            return result;

        while (reader.Read())
        {
            if (reader.TokenType == JsonToken.EndObject)
                break;

            if (reader.TokenType != JsonToken.PropertyName)
                continue;

            var keyStr = reader.Value.ToString();
            if (!keyStr.StartsWith("0x"))
                throw new JsonSerializationException($"Expected hexadecimal key, got {keyStr} instead");

            if (!uint.TryParse(keyStr.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var key))
                throw new JsonSerializationException($"Invalid hexadecimal key: {keyStr}");

            reader.Read();
            var value = serializer.Deserialize<T>(reader);
            result.Add(key, value);
        }

        return result;
    }

    public override void WriteJson(JsonWriter writer, Dictionary<uint, T> value, JsonSerializer serializer)
    {
        writer.WriteStartObject();
        foreach (var kvp in value)
        {
            writer.WritePropertyName($"0x{kvp.Key:X}");
            serializer.Serialize(writer, kvp.Value);
        }
        writer.WriteEndObject();
    }
}

使用方式:

  • 全局注册(针对特定T类型):
var settings = new JsonSerializerSettings();
settings.Converters.Add(new UIntKeyDictionaryConverter<MyType>());
// 若有多个T类型,可添加多个对应转换器实例
  • 按需标记属性:
public class ComplexDomainObject
{
    [JsonConverter(typeof(UIntKeyDictionaryConverter<MyType>))]
    public Dictionary<uint, MyType> SomeDictionary { get; set; }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 08:36:10