【问题标题】:JSON.NET custom constructorJSON.NET 自定义构造函数
【发布时间】:2013-12-17 18:48:25
【问题描述】:

作为这个问题JSON.NET CustomCreationConverter with nested objects 的部分问题,我尝试在反序列化期间调用自定义构造函数。我简化的类层次结构如下:

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 方法,当然不能从这个信息中创建正确的类型。

How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects的启发,我实现了一个转换器,如下所示:

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.Entities.Tests.Unit.EditableObjectCollectionTests+TestEditableObject]”上。路径“$type”,第 1 行,位置 47。

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

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

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

任何提示都非常感谢,在此先感谢 卡斯滕

【问题讨论】:

    标签: c# constructor json.net deserialization converter


    【解决方案1】:

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

    似乎转换器应该返回一个仍然具有相同 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;
            }
        }
    

    我希望这对某人有所帮助。

    最好的问候, 卡斯滕

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-17
      • 2011-02-22
      • 2015-10-30
      • 1970-01-01
      相关资源
      最近更新 更多