问题
I am consuming a RESTful Web service sending JSON, that I try to deserialize using HttpContent.ReadAsAsync<T>
. The type I try to deserialize to declares a property that returns an IEnumerable containing an interface type. This code snippet demonstrates the kind of type I'm trying to deserialize to:
public class Data
{
public IEnumerable<IChild> Children { get; set; };
}
The problem is that Newtonsoft.Json, underlying HttpContent.ReadAsAsync<T>
doesn't understand how to deserialize objects of type IChild
, the latter being an interface. How can I specify to Newtonsoft.Json how to deserialize IChild to a concrete type?
回答1:
You can use a custom Converter
to tell JSON.NET how to deserialize types of that interface. The code below shows an example.
public class StackOverflow_12197892
{
public class Data
{
public IEnumerable<IChild> Children { get; set; }
public override string ToString()
{
return string.Format("Data{{Children=[{0}]}}",
string.Join(", ", Children.Select(c => string.Format("{0}/{1}", c.Name, c.IsFemale ? "girl" : "boy"))));
}
}
public interface IChild
{
string Name { get; }
bool IsFemale { get; }
}
public class Son : IChild
{
public Son(string name)
{
this.Name = name;
}
public string Name { get; private set; }
public bool IsFemale { get { return false; } }
}
public class Daughter : IChild
{
public Daughter(string name)
{
this.Name = name;
}
public string Name { get; private set; }
public bool IsFemale { get { return true; } }
}
class ChildConverter : Newtonsoft.Json.JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(IChild).IsAssignableFrom(objectType);
}
public override object ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
JObject obj = serializer.Deserialize<JToken>(reader) as JObject;
if (obj != null)
{
bool isFemale = obj["isFemale"].ToObject<bool>();
string name = obj["name"].ToObject<string>();
if (isFemale)
{
return new Daughter(name);
}
else
{
return new Son(name);
}
}
else
{
return null;
}
}
public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public static void Test()
{
Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
serializer.Converters.Add(new ChildConverter());
string json = "{'Children':[{'name':'John',isFemale:false},{'name':'Mary',isFemale:true}]}".Replace('\'', '\"');
var obj = serializer.Deserialize(new StringReader(json), typeof(Data));
Console.WriteLine(obj);
}
}
回答2:
It is quite simple and out of the box support provided by json.net, you just have to use the following JsonSettings while serializing and Deserializing:
JsonConvert.SerializeObject(graph,Formatting.None, new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple
});
and for Deserialzing use the below code:
JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bData),type,
new JsonSerializerSettings()
{TypeNameHandling = TypeNameHandling.Objects});
Just take a note of the JsonSerializerSettings object initializer, that is important for you.
来源:https://stackoverflow.com/questions/12197892/using-newtonsoft-json-how-do-i-deserialize-json-to-a-type-with-an-ienumerable-p