Mic*_*uso 12 c# serialization json converter json.net
我总觉得JSON序列化程序实际遍历整个对象的树,并在它遇到的每个接口类型对象上执行自定义JsonConverter的WriteJson函数 - 不是这样.
我有以下类和接口:
public interface IAnimal
{
string Name { get; set; }
string Speak();
List<IAnimal> Children { get; set; }
}
public class Cat : IAnimal
{
public string Name { get; set; }
public List<IAnimal> Children { get; set; }
public Cat()
{
Children = new List<IAnimal>();
}
public Cat(string name="") : this()
{
Name = name;
}
public string Speak()
{
return "Meow";
}
}
public class Dog : IAnimal
{
public string Name { get; set; }
public List<IAnimal> Children { get; set; }
public Dog()
{
Children = new List<IAnimal>();
}
public Dog(string name="") : this()
{
Name = name;
}
public string Speak()
{
return "Arf";
}
}
Run Code Online (Sandbox Code Playgroud)
为了避免JSON中的$ type属性,我编写了一个自定义JsonConverter类,其WriteJson是
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JToken t = JToken.FromObject(value);
if (t.Type != JTokenType.Object)
{
t.WriteTo(writer);
}
else
{
IAnimal animal = value as IAnimal;
JObject o = (JObject)t;
if (animal != null)
{
if (animal is Dog)
{
o.AddFirst(new JProperty("type", "Dog"));
//o.Find
}
else if (animal is Cat)
{
o.AddFirst(new JProperty("type", "Cat"));
}
foreach(IAnimal childAnimal in animal.Children)
{
// ???
}
o.WriteTo(writer);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,是的,一只狗可以为孩子养猫,反之亦然.在转换器中,我想插入"type"属性,以便将其保存到序列化中.我有以下设置.(动物园只有一个名字和一个IAnimals列表.为了简洁和懒惰,我没有把它包括在内;))
Zoo hardcodedZoo = new Zoo()
{ Name = "My Zoo",
Animals = new List<IAnimal> { new Dog("Ruff"), new Cat("Cleo"),
new Dog("Rover"){
Children = new List<IAnimal>{ new Dog("Fido"), new Dog("Fluffy")}
} }
};
JsonSerializerSettings settings = new JsonSerializerSettings(){
ContractResolver = new CamelCasePropertyNamesContractResolver() ,
Formatting = Formatting.Indented
};
settings.Converters.Add(new AnimalsConverter());
string serializedHardCodedZoo = JsonConvert.SerializeObject(hardcodedZoo, settings);
Run Code Online (Sandbox Code Playgroud)
serializedHardCodedZoo 序列化后具有以下输出:
{
"name": "My Zoo",
"animals": [
{
"type": "Dog",
"Name": "Ruff",
"Children": []
},
{
"type": "Cat",
"Name": "Cleo",
"Children": []
},
{
"type": "Dog",
"Name": "Rover",
"Children": [
{
"Name": "Fido",
"Children": []
},
{
"Name": "Fluffy",
"Children": []
}
]
}
]
}
Run Code Online (Sandbox Code Playgroud)
类型属性显示在Ruff,Cleo和Rover上,但不适用于Fido和Fluffy.我猜WriteJson不是递归调用的.我如何在那里获得那种类型的财产?
顺便说一句,为什么它不是像我期望的那样的驼峰式IAnimals?
Bri*_*ers 19
您的转换器未应用于子对象的原因是因为JToken.FromObject()在内部使用了一个新的串行器实例,而不知道您的转换器.有一个允许你传入序列化程序的重载,但是如果你这样做会有另一个问题:因为你在转换器中并且你正在JToken.FromObject()尝试序列化父对象,你将进入无限递归环.(JToken.FromObject()调用串行器,调用转换器,调用JToken.FromObject()等)
若要解决此问题,您必须手动处理父对象.您可以使用一些反射来枚举父属性,而不会有太多麻烦:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JObject jo = new JObject();
Type type = value.GetType();
jo.Add("type", type.Name);
foreach (PropertyInfo prop in type.GetProperties())
{
if (prop.CanRead)
{
object propVal = prop.GetValue(value, null);
if (propVal != null)
{
jo.Add(prop.Name, JToken.FromObject(propVal, serializer));
}
}
}
jo.WriteTo(writer);
}
Run Code Online (Sandbox Code Playgroud)
小提琴:https://dotnetfiddle.net/sVWsE4
| 归档时间: |
|
| 查看次数: |
16286 次 |
| 最近记录: |