dth*_*her 84 .net serialization json.net
我有一个类定义,其中包含一个返回接口的属性.
public class Foo
{
public int Number { get; set; }
public ISomething Thing { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
尝试使用Json.NET序列化Foo类给出了一条错误消息,例如"无法创建类型为'ISomething'的实例.ISomething可能是一个接口或抽象类."
是否有Json.NET属性或转换器可以让我指定Something在反序列化期间使用的具体类?
Dan*_* T. 87
您可以使用Json.NET做的一件事是:
var settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Objects;
JsonConvert.SerializeObject(entity, Formatting.Indented, settings);
Run Code Online (Sandbox Code Playgroud)
该TypeNameHandling标志将向$typeJSON 添加一个属性,这允许Json.NET知道将对象反序列化所需的具体类型.这允许您在仍然满足接口或抽象基类的同时反序列化对象.
然而,缺点是这是特定于Json.NET的.这$type将是一个完全限定的类型,因此如果您使用类型信息对其进行序列化,则反序列化器也需要能够理解它.
MrM*_*son 49
您可以通过使用JsonConverter类来实现此目的.假设您有一个具有接口属性的类;
public class Organisation {
public string Name { get; set; }
[JsonConverter(typeof(TycoonConverter))]
public IPerson Owner { get; set; }
}
public interface IPerson {
string Name { get; set; }
}
public class Tycoon : IPerson {
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
您的JsonConverter负责序列化和反序列化底层属性;
public class TycoonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(IPerson));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return serializer.Deserialize<Tycoon>(reader);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Left as an exercise to the reader :)
throw new NotImplementedException();
}
}
Run Code Online (Sandbox Code Playgroud)
当您使用通过Json.Net反序列化的组织时,Owner属性的基础IPerson将是Tycoon类型.
Erh*_*ung 39
如前所述,您不必使用TypeNameHandling.Objects选项将自定义JsonSerializerSettings对象传递给JsonConvert.SerializeObject(),而只需使用属性标记该特定接口属性,这样生成的JSON就不会因"$ type"属性而膨胀在每个对象上:
public class Foo
{
public int Number { get; set; }
// Add "$type" property containing type info of concrete class.
[JsonProperty( TypeNameHandling = TypeNameHandling.Objects )]
public ISomething { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
Sam*_*vis 22
在最新版本的第三方Newtonsoft Json转换器中,您可以设置一个具有与interfaced属性相关的具体类型的构造函数.
public class Foo
{
public int Number { get; private set; }
public ISomething IsSomething { get; private set; }
public Foo(int number, Something concreteType)
{
Number = number;
IsSomething = concreteType;
}
}
Run Code Online (Sandbox Code Playgroud)
只要Something实现ISomething,这应该有效.如果JSon转换器尝试使用它,也不要放置默认的空构造函数,必须强制它使用包含具体类型的构造函数.
PS.这也允许您将您的setter设为私有.
小智 17
有同样的问题,所以我想出了我自己的转换器,它使用已知的类型参数.
public class JsonKnownTypeConverter : JsonConverter
{
public IEnumerable<Type> KnownTypes { get; set; }
public JsonKnownTypeConverter(IEnumerable<Type> knownTypes)
{
KnownTypes = knownTypes;
}
protected object Create(Type objectType, JObject jObject)
{
if (jObject["$type"] != null)
{
string typeName = jObject["$type"].ToString();
return Activator.CreateInstance(KnownTypes.First(x =>typeName.Contains("."+x.Name+",")));
}
throw new InvalidOperationException("No supported type");
}
public override bool CanConvert(Type objectType)
{
if (KnownTypes == null)
return false;
return (objectType.IsInterface || objectType.IsAbstract) && KnownTypes.Any(objectType.IsAssignableFrom);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
var target = Create(objectType, jObject);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Run Code Online (Sandbox Code Playgroud)
我为反序列化和序列化定义了两种扩展方法:
public static class AltiJsonSerializer
{
public static T DeserializeJson<T>(this string jsonString, IEnumerable<Type> knownTypes = null)
{
if (string.IsNullOrEmpty(jsonString))
return default(T);
return JsonConvert.DeserializeObject<T>(jsonString,
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Converters = new List<JsonConverter>
(
new JsonConverter[]
{
new JsonKnownTypeConverter(knownTypes)
}
)
}
);
}
public static string SerializeJson(this object objectToSerialize)
{
return JsonConvert.SerializeObject(objectToSerialize, Formatting.Indented,
new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.Auto});
}
}
Run Code Online (Sandbox Code Playgroud)
您可以定义自己的比较和识别转换类型的方式,我只使用类名.
ram*_*ram -10
这里参考了ScottGu 写的一篇文章
基于此,我编写了一些我认为可能有用的代码
public interface IEducationalInstitute
{
string Name
{
get; set;
}
}
public class School : IEducationalInstitute
{
private string name;
#region IEducationalInstitute Members
public string Name
{
get { return name; }
set { name = value; }
}
#endregion
}
public class Student
{
public IEducationalInstitute LocalSchool { get; set; }
public int ID { get; set; }
}
public static class JSONHelper
{
public static string ToJSON(this object obj)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(obj);
}
public static string ToJSON(this object obj, int depth)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RecursionLimit = depth;
return serializer.Serialize(obj);
}
}
Run Code Online (Sandbox Code Playgroud)
这就是你所说的
School myFavSchool = new School() { Name = "JFK High School" };
Student sam = new Student()
{
ID = 1,
LocalSchool = myFavSchool
};
string jSONstring = sam.ToJSON();
Console.WriteLine(jSONstring);
//Result {"LocalSchool":{"Name":"JFK High School"},"ID":1}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确的话,我认为您不需要指定一个实现 JSON 序列化接口的具体类。
| 归档时间: |
|
| 查看次数: |
87570 次 |
| 最近记录: |