我有一个需要序列化/反序列化的类。它看起来像这样:
public class Animation
{
[JsonProperty]
private readonly string name;
[JsonProperty]
private readonly IList<Rectangle> frames;
}
然而,Json.Net与XNA的Rectangle
类并不相称。它需要一个自定义JsonConverter
,我managed to scrape together。这适用于具有单个Rectangle
属性的类,例如:
public class Sprite
{
[JsonConverter(typeof(RectangleConverter))]
[JsonProperty]
private readonly Rectangle frame;
}
但是如何将该转换器应用到我Rectangle
班级的Animation
列表中?
答案 0 :(得分:1)
根据the doc,XNA Rectangle
结构标记为TypeConverter
,默认情况下类型为转换器always return true when asked to convert to string。因此,Json.Net默认会尝试创建字符串契约而不是对象契约,这会在与RectangleConverter一起使用时导致错误。这可以通过使用自定义ContractResolver
来告诉Json.Net将Rectangle
视为对象而不是字符串。我们还可以在解析器中设置转换器,因此您无需在[JsonConverter]
处使用Rectangle
属性修饰类属性。
以下是您需要的代码:
class CustomResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
if (objectType == typeof(Rectangle) || objectType == typeof(Rectangle?))
{
JsonContract contract = base.CreateObjectContract(objectType);
contract.Converter = new RectangleConverter();
return contract;
}
return base.CreateContract(objectType);
}
}
要使用解析器,请将其添加到序列化设置并将其传递给DeserializeObject()
或SerializeObject()
,如下所示:
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
Animation anim = JsonConvert.DeserializeObject<Animation>(json, settings);
答案 1 :(得分:1)
希望有人为我提供更好的解决方案(必须有一个),但这对我现在很有用:
public class RectangleListConverter : RectangleConverter
{
public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer )
{
var rectangleList = (IList<Rectangle>)value;
var jArray = new JArray();
foreach ( var rectangle in rectangleList )
{
jArray.Add( GetObject( rectangle ) );
}
jArray.WriteTo( writer );
}
public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
{
var rectangleList = new List<Rectangle>();
var jArray = JArray.Load( reader );
foreach ( var jToken in jArray )
{
rectangleList.Add( GetRectangle( jToken ) );
}
return rectangleList;
}
public override bool CanConvert( Type objectType )
{
throw new NotImplementedException();
}
}
我必须修改我正在使用的RectangleConverter
:
public class RectangleConverter : JsonConverter
{
public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer )
{
var rectangle = (Rectangle)value;
var jObject = GetObject( rectangle );
jObject.WriteTo( writer );
}
public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
{
var jObject = JObject.Load( reader );
return GetRectangle( jObject );
}
public override bool CanConvert( Type objectType )
{
throw new NotImplementedException();
}
protected static JObject GetObject( Rectangle rectangle )
{
var x = rectangle.X;
var y = rectangle.Y;
var width = rectangle.Width;
var height = rectangle.Height;
return JObject.FromObject( new { x, y, width, height } );
}
protected static Rectangle GetRectangle( JObject jObject )
{
var x = GetTokenValue( jObject, "x" ) ?? 0;
var y = GetTokenValue( jObject, "y" ) ?? 0;
var width = GetTokenValue( jObject, "width" ) ?? 0;
var height = GetTokenValue( jObject, "height" ) ?? 0;
return new Rectangle( x, y, width, height );
}
protected static Rectangle GetRectangle( JToken jToken )
{
var jObject = JObject.FromObject( jToken );
return GetRectangle( jObject );
}
protected static int? GetTokenValue( JObject jObject, string tokenName )
{
JToken jToken;
return jObject.TryGetValue( tokenName, StringComparison.InvariantCultureIgnoreCase, out jToken ) ? (int)jToken : (int?)null;
}
}
具有新JsonConverter
属性的动画类:
public class Animation
{
[JsonProperty]
private readonly string name;
[JsonConverter(typeof(RectangleListConverter))]
[JsonProperty]
private readonly IList<Rectangle> frames;
}