JSON.NET自定义构造函数



作为这个问题的一个部分问题,带有嵌套对象的JSON.NET CustomCreationConverter我试图在反序列化过程中调用自定义构造函数。我简化的类层次结构如下:

public abstract class BusinessObjectBase
{
    internal BusinessObjectBase(SerializationContext context)
        : base(context)
    {
    }
}
public abstract class EditableObjectBase : BusinessObjectBase
{
    protected EditableObjectBase(SerializationContext context)
        : base(context)
    {
    }
}
public class EditableObjectCollection<TObject> : BusinessObjectBase, ICollection<TObject>, IList, INotifyCollectionChanged where TObject : BusinessObjectBase
{
    protected EditableObjectCollection(SerializationContext context)
        : base(context)
    {
    }
}

我对对象层次结构有一定的了解,但用户可以/被迫派生自己的类。我的想法是编写一个自定义创建转换器。我要解决的问题是,序列化对象中的属性可以声明为抽象的BusinessObjectBase,但实际对象将是一个更派生的类,可能是集合,也可能不是集合。CustomCreationConverter只将此抽象类型传递给Create方法,当然无法根据此信息创建正确的类型。

受此启发如何在JSON.NET中实现自定义JsonConverter以反序列化基类对象列表我实现了一个转换器,如下所示:

internal class BusinessObjectCreationConverter : JsonConverter
{
    public override bool CanWrite
    {
        get
        {
            return false;
        }
    }
    public override bool CanConvert(Type objectType)
    {
        return typeof(BusinessObjectBase).IsAssignableFrom(objectType);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        object result = null;
        if (reader.TokenType != JsonToken.Null)
        {
            JObject jsonObject = JObject.Load(reader);
            result = this.Create(objectType, jsonObject);
            Verification.Assert<NullReferenceException>(result != null, "No Business Object created.");
            serializer.Populate(jsonObject.CreateReader(), result);
        }
        return result;
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
    }
    public BusinessObjectBase Create(Type objectType, JObject jsonObject)
    {
        JToken token       = jsonObject.SelectToken("$type");
        var typeString     = token.Value<string>();
        Type type          = Type.GetType(typeString);
        var businessObject = type.CreateUsingDesrializationConstructor<BusinessObjectBase>();
        businessObject.Initialize(true);
        return businessObject;
    }
}

我要测试序列化的类如下:

public class AnyPocoContainingBusinessObject
{
    public BusinessObjectBase BusinessObject { get; set; }    
}
public class TestEditableObject : EditableObjectBase
{
    internal TestEditableObject(SerializationContext context)
        : base(context)
    {
    }
 }

如果我用集合初始化我的类

var collection = new EditableObjectCollection<TestEditableObject>(null);
var poco = new AnyPocoContainingBusinessObject { BusinessObject = collection };

并以这种方式配置串行器:

    public NewtonsoftJsonSerializer()
        : this(new JsonSerializer
        {
            TypeNameHandling = TypeNameHandling.Auto,
            ObjectCreationHandling = ObjectCreationHandling.Replace,
            PreserveReferencesHandling = PreserveReferencesHandling.Objects,
            ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
            DefaultValueHandling = DefaultValueHandling.Ignore,
            ContractResolver = new KsJsonContractResolver()
        })
    {
        this.serializer.Converters.Add(new ReadOnlyObjectCollectionConverter());
        this.serializer.Converters.Add(new BusinessObjectCreationConverter());
        this.serializer.TraceWriter = new ConsoleTraceWriter();
    }

我得到一个例外:无法将JSON对象填充到类型"KS.Interfaces.Core.Entities.EditableObjectCollection`1[KS.Interfaces.Core.Editives.Tests.Unit.EditableObject CollectionTests+TestEditableObject]"中。路径"$type",第1行,位置47。

在我的转换器的代码行中:

serializer.Populate(jsonObject.CreateReader(), result);

有人能告诉我可能是什么原因吗?我确信我创建了正确的类型,并且使用EditableObjectBase派生的对象,一切都很好。只有收藏似乎不起作用。

非常感谢任何提示,提前感谢Carsten

即使我还没有找到让转换器工作的方法,但在调试问题时我学到了一件事:

转换器似乎应该返回一个仍然具有相同JsonToken值的对象。在我的例子中,原始对象的JsonToken是JsonToken.object,但对于我的转换结果,正确的令牌值应该是JsonToken。Array,但读者仍然可以看到JsonToken。object。在这一点上,我停止了研究,因为我找到了一种更好的方法来调用我的自定义构造函数。

我写了自己的合同解析程序:

   internal class BusinessBaseContractResolver : DefaultContractResolver
   {
        public BusinessBaseContractResolver()
        {
            this.DefaultMembersSearchFlags |= BindingFlags.NonPublic;    
        }
        public override JsonContract ResolveContract(Type type)
        {
            JsonContract contract = base.ResolveContract(type);
            if (typeof(BusinessObjectBase).IsAssignableFrom(type))
            {
                contract.DefaultCreator = delegate
                {
                    var businessObject = type.CreateUsingDeserializationConstructor<BusinessObjectBase>();
                    businessObject.Initialize(true);
                    return businessObject;
                };
            }
            return contract;
        }
    }

我希望这能帮助到别人。

谨致问候,Carsten

相关内容

  • 没有找到相关文章

最新更新