作为此问题的部分问题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派生对象一切都很好。只有集合似乎不起作用。
任何提示都非常感谢,提前谢谢 卡斯滕
答案 0 :(得分: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;
}
}
我希望这有助于某人。
祝你好运, 卡斯滕