问题描述
通常,对于派生类型的反序列化,您必须定义一个自定义转换器。我的意思是,当有一个基类- Base 和其他从 Base 派生的类时。在这种情况下,您必须定义一个自定义转换器,并使用每个派生类中的一些数据(可能是一个枚举)来知道将数据转换为哪种类型。问题是当调用此转换器作为参考值时,其表示形式类似于{"$ref":"1"}
,而转换器无法从中获取任何信息。
有什么想法如何处理吗?
这里是更好理解的来源:
public enum ElementType
{
Invalid = 0,FirstElement,SecondElement
}
public class SubElement
{
[JsonConstructor]
private SubElement() { }
public SubElement(string name,Element parent)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("message",nameof(name));
}
Name = name;
Parent = parent ?? throw new ArgumentNullException(nameof(parent));
}
[JsonProperty]
public string Name { get; private set; }
[JsonProperty]
public Element Parent { get; private set; }
}
[JsonObject(IsReference = true)]
[JsonConverter(typeof(BaseConverter))]
public abstract class Element
{
[JsonConstructor]
protected Element() { }
public Element(string name,IList<SubElement> subelements)
{
Name = name;
Subelements = subelements;
}
[JsonProperty]
public string Name { get; private set; }
[JsonProperty]
public IList<SubElement> Subelements { get; private set; }
public abstract ElementType Type { get; }
}
public class FirstElement : Element
{
[JsonConstructor]
private FirstElement() { }
public FirstElement(string name,IList<SubElement> subelements) : base(name,subelements) { }
public override ElementType Type => ElementType.FirstElement;
}
public class BaseConverter : CustomCreationConverter<Element>
{
private ElementType elementType;
public override object ReadJson(JsonReader reader,Type objectType,object existingValue,JsonSerializer serializer)
{
var obj = JObject.ReadFrom(reader);
elementType = obj["Type"].ToObject<ElementType>();
return base.ReadJson(obj.CreateReader(),objectType,existingValue,serializer);
}
public override Element Create(Type objectType)
{
switch (elementType)
{
case ElementType.FirstElement:
return Activator.CreateInstance(typeof(FirstElement),true) as Element;
default:
throw new NotImplementedException();
}
}
}
class Program
{
static void Main(string[] args)
{
Element firstElement = new FirstElement("FirstElement",new List<SubElement>());
firstElement.Subelements.Add(new SubElement("Subelement1",firstElement));
firstElement.Subelements.Add(new SubElement("Subelement2",firstElement));
string serialized = JsonConvert.SerializeObject(firstElement);
Console.WriteLine(serialized);
Element deserialized = JsonConvert.DeserializeObject<Element>(serialized);
}
}
序列化输出:
{
"$id": "1","Type": 1,"Name": "FirstElement","Subelements": [
{
"Name": "Subelement1","Parent": {
"$ref": "1"
}
},{
"Name": "Subelement2","Parent": {
"$ref": "1"
}
}
]
}
解决方法
如果有人面对相同的情况,我发现了一种解决方法,方法是在 BaseConverter 类中添加字典,该字典在 Create 中创建时按其$id
映射元素。 em>方法,当当前对象是$ref
时,ReadJson
方法将返回对应的映射元素。