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

C#中appsettings.json转类对象遇IConvertible实现问题

问题描述

appsettings 配置

"testData": [
    {
      "target": "MarketMirrorClient.GetContests",
      "mockData": [
        {
          "request": {
            "contestKeys": [ "testContestKey1" ]
          },
          "response": {
            "contests": [
              {
                "contestKey": "testContestKey1",
                "contestType": "football",
                "contestStatus": "InPlay"
              }
            ]
          }
        },
        {
          "request": {
            "contestKeys": [ "testContestKey2" ]
          },
          "response": {
            "contests": [
              {
                "contestKey": "testContestKey2",
                "contestType": "soccer",
                "contestStatus": "PreGame"
              }
            ]
          }
        }
      ]
    }
  ]

模型类代码

public class MockTestData
{
    public List<TestData> TestData { get; set; } = new();
}

public class TestData
{
    public string Target { get; set; }
    public List<MockData> MockData { get; set; } = new();
}

public class MockData
{
    public Dictionary<string, object> Request { get; set; }
    public object Response { get; set; }
}

问题场景

执行 builder.Services.Configure<MockTestData>("testData"); 绑定配置时,testData.mockData.request 被序列化为 Dictionary<string, object>,但从字典中取出对象转换为特定类型(如 List<string>)时,抛出需实现 IConvertible 的异常。尝试将类型改为 dynamic 或 ExpandoObject,要么仍提示需要 IConvertible,要么无法转换为目标类型。


解决方案

不需要手动实现 IConvertible,问题根源在于配置绑定的类型匹配逻辑,以下是几种可行处理方式:

1. 强类型绑定替代字典

如果Request的结构固定,直接定义对应强类型类,避免使用 Dictionary<string, object>:

// 新增Request的强类型类
public class ContestRequest
{
    public List<string> ContestKeys { get; set; } = new();
}

// 修改MockData类
public class MockData
{
    public ContestRequest Request { get; set; }
    public object Response { get; set; }
}

配置绑定时会直接将contestKeys序列化为List<string>,无需后续手动转换,自然不会触发IConvertible异常。

2. 自定义配置绑定转换器

如果Request结构不固定必须用字典,可自定义类型转换器处理object到目标类型的转换(以Newtonsoft.Json为例):

public class ObjectToListConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(List<>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartArray)
        {
            var listType = objectType.GetGenericArguments()[0];
            var list = Activator.CreateInstance(objectType);
            var addMethod = objectType.GetMethod("Add");
            
            while (reader.Read() && reader.TokenType != JsonToken.EndArray)
            {
                var item = serializer.Deserialize(reader, listType);
                addMethod.Invoke(list, new[] { item });
            }
            return list;
        }
        return existingValue;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

注册转换器并完成配置绑定:

builder.Services.Configure<MockTestData>(options =>
{
    var configSection = builder.Configuration.GetSection("testData");
    var rawJson = configSection.GetRawJson();
    JsonConvert.PopulateObject(rawJson, options, new JsonSerializerSettings
    {
        Converters = { new ObjectToListConverter() }
    });
});

3. 序列化工具手动转换

如果不想修改绑定逻辑,从字典取到object后,用Json序列化工具重新反序列化为目标类型:

// 从Request字典中取出contestKeys对象
var contestKeysObj = mockData.Request["contestKeys"];
// 通过序列化再反序列化完成类型转换
var contestKeys = JsonConvert.DeserializeObject<List<string>>(JsonConvert.SerializeObject(contestKeysObj));

这种方式利用Json工具的类型转换能力,绕开IConvertible的要求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 03:05:57