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

使用JsonConvert.DeserializeObject结合DynamicObject等处理无默认构造函数的EntityBase

没问题,我来给你一步步解决这个反序列化的问题!你的EntityBase继承了DynamicObject又没有无参构造函数,确实需要自定义转换器来告诉Json.NET怎么正确创建实例并处理动态属性。下面是具体的实现方案:

核心思路

要实现这个需求,我们需要自定义一个继承自TypeCreationConverter<EntityBase>的转换器,它的作用有两个:

  1. 调用EntityBase的带参构造函数创建实例
  2. 把JSON中的动态属性映射到EntityBase内部的values字典中

1. 编写自定义转换器EntityBaseConverter

这个转换器会负责实例创建和属性赋值,因为values是私有字段,我们需要用反射来访问它(如果你的类能提供公开的属性添加方法,优先用公开方法更符合封装原则):

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using System.Reflection;

public class EntityBaseConverter : TypeCreationConverter<EntityBase>
{
    // 重写Create方法,调用带参构造函数创建实例
    protected override EntityBase Create(Type objectType, JObject jObject)
    {
        // 从JSON中提取构造函数需要的EntityName参数
        var entityName = jObject["EntityName"]?.Value<string>();
        if (string.IsNullOrWhiteSpace(entityName))
        {
            throw new JsonSerializationException("JSON中必须包含EntityName字段,否则无法创建EntityBase实例");
        }
        return new EntityBase(entityName);
    }

    // 重写ReadJson方法,处理动态属性赋值
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jObject = JObject.Load(reader);
        // 先调用Create方法获取实例
        var entity = Create(objectType, jObject);

        // 获取私有values字典的字段信息
        var valuesField = typeof(EntityBase).GetField(
            "values", 
            BindingFlags.NonPublic | BindingFlags.Instance);
        
        if (valuesField == null)
        {
            throw new JsonSerializationException("无法找到EntityBase的私有values字段");
        }

        var valuesDict = (Dictionary<string, object>)valuesField.GetValue(entity);

        // 遍历JSON中的所有属性,除了EntityName,都存入values字典
        foreach (var prop in jObject.Properties())
        {
            if (prop.Name != nameof(EntityBase.EntityName))
            {
                valuesDict[prop.Name] = prop.Value.ToObject(prop.Value.Type, serializer);
            }
        }

        return entity;
    }
}

2. 配置Json.NET使用转换器

有两种方式可以让Json.NET使用这个转换器,选其中一种即可:

方式一:给EntityBase类添加特性标记

直接在你的EntityBase类上加上JsonConverter特性,这样每次序列化/反序列化都会自动使用这个转换器:

[JsonConverter(typeof(EntityBaseConverter))]
public class EntityBase : DynamicObject
{
    // 你的类原有代码...
    public string EntityName { get; private set; }
    private readonly Dictionary<string, object> values = new Dictionary<string, object>();

    public EntityBase(string entityName)
    {
        this.EntityName = entityName;
    }

    public virtual object this[string fieldname]
    {
        get => values.TryGetValue(fieldname, out var val) ? val : null;
        set => values[fieldname] = value;
    }

    // 记得重写TryGetMember和TrySetMember,让动态属性访问生效
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return values.TryGetValue(binder.Name, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        values[binder.Name] = value;
        return true;
    }
}

方式二:反序列化时手动传入转换器设置

如果不想修改类的特性,可以在反序列化时创建JsonSerializerSettings并添加转换器:

var json = @"{""EntityName"":""Customer"", ""Age"":30, ""Name"":""John""}";

var settings = new JsonSerializerSettings();
settings.Converters.Add(new EntityBaseConverter());

var entity = JsonConvert.DeserializeObject<EntityBase>(json, settings);

3. 测试验证

你可以用下面的代码测试反序列化效果,不管是通过索引器还是动态类型访问属性都能正常工作:

static void Main(string[] args)
{
    var json = @"{""EntityName"":""Product"", ""Price"":99.99, ""Stock"":100}";
    var entity = JsonConvert.DeserializeObject<EntityBase>(json);

    // 通过索引器访问
    Console.WriteLine($"EntityName: {entity.EntityName}");
    Console.WriteLine($"Price: {entity["Price"]}");

    // 通过动态类型访问(因为继承了DynamicObject)
    dynamic dynEntity = entity;
    Console.WriteLine($"Stock: {dynEntity.Stock}");
}

注意事项

  • 如果你的EntityBase后续能提供公开的方法(比如AddField(string key, object value))来操作values字典,建议替换掉反射逻辑,这样代码更安全也更易维护。
  • 确保JSON中必须包含EntityName字段,否则转换器会抛出异常,你可以根据自己的需求调整异常处理逻辑(比如给个默认值)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:00:40