以下是我的例子:
JSON请求字符串:
{
entity: '09f7cb28-0464-41c8-a20d-1b05eb1cda0a'
}
我的请求对象:
public class Request {
public Request() { }
[JsonProperty("entity")]
private string EntityIdentifier { get; set; }
public EntityObject Entity { get; set; }
}
我有这个工作,以便将字符串传递给EntityIdentifier,这很好,然后在我的代码中我找到使用实体标识符属性的实际实体,用找到的实体填充Entity属性但是这就是我序列化对象时得到的结果:
{
entity: '09f7cb28-0464-41c8-a20d-1b05eb1cda0a',
Entity: {
// my object's properties
}
}
当我真正想要的是:
{
entity: {
// my object's properties
}
}
现在,我知道我可以把它分成两个不同的类,我可能不得不这样做,但是如果有办法将它们保存在同一个类中,它会很棒并且节省了大量的编码时间
澄清因为我似乎没有很好地解释我想要的东西:
免责声明:这不存在(AFAIK),但这是我想要的:
public class Request {
public Request() { }
[JsonProperty("entity", OnlyWhen=Deserializing)]
private string EntityIdentifier { get; set; }
[JsonProperty("entity", OnlyWhen=Serializing)]
public EntityObject Entity { get; set; }
}
这就是我真正希望实现的目标,但据我所知,唯一可以实际将这类代码放在自定义转换器中的地方,但不幸的是,我似乎无法做到确定转换器在使用时是用于序列化还是反序列化。
答案 0 :(得分:1)
我相信你只需要用[ScriptIgnore]和/或[JsonIgnore]标记实体,就像这样:
[ScriptIgnore]
[JsonIgnore]
public EntityObject Entity { get; set; }
我听说JsonIgnore有时不工作。使用两者可能是你最好的选择。
另外 - 我认为在描述问题时你的措辞不正确。你声明:"这是我在反序列化对象时得到的结果" - 实际上,我相信你的意思是说"序列化"。
如果在设置EntityIdentifier时需要填充Entity,则将EntityIdentifier的代码替换为:
string _eId;
[JsonProperty("entity")]
private string EntityIdentifier
{
get{return _eId;}
set
{
_eId = value;
Entity = someMethodToRetrieveTheEntityById(_eId);
}
}
答案 1 :(得分:1)
如何使用JsonIgnore属性?
public class Request
{
public Request() { }
[JsonIgnore]
private string EntityIdentifier { get; set; }
[JsonProperty("entity")]
public EntityObject Entity { get; set; }
}
答案 2 :(得分:1)
这里的问题可能是你试图迫使一个班级做两个人的工作。为什么不这样做:
// Deserialize requests into this.
public class EntityRequest
{
[JsonProperty("entity")]
private string EntityIdentifier { get; set; }
}
// Serialize these to file/etc.
public class EntityData
{
[JsonProperty("entity")]
public EntityObject Entity { get; set; }
}
然后将请求反序列化为EntityRequest对象,使用EntityRequest和其他一些逻辑加载EntityData对象,然后将EntityData对象序列化为file。这里的JsonProperty属性意味着请求和输出实体都被称为'实体'就像你的OP一样。这似乎是您之后的工作流程。
将所有内容塞进一个类中会使这个问题变得更加复杂。
答案 3 :(得分:0)
您可以使用与此类似的自定义JsonConverter
来解决此问题:
public class RequestConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Request));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// On deserialization, the JSON has an entity identifier (GUID)
// so use it to retrieve the actual object from the database.
JToken token = JToken.Load(reader);
Request req = new Request();
req.Entity = RetrieveFromDatabase(token["entity"].ToString());
return req;
}
private EntityObject RetrieveFromDatabase(string entityIdentifier)
{
// Implement this method to retrieve the actual EntityObject from the DB.
// (Return null if the object is not found.)
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// On serialization, write out just the entity object properties
Request req = (Request)value;
JObject obj = new JObject();
obj.Add("entity", JToken.FromObject(req.Entity));
obj.WriteTo(writer);
}
}
要使用转换器,只需使用Request
属性装饰[JsonConverter]
类,如下所示。请注意,您可以删除私有EntityIdentifier
属性,因为它将不再需要。转换器负责根据JSON中的标识符从数据库中检索EntityObject
。
[JsonConverter(typeof(RequestConverter))]
public class Request
{
public Request() { }
public EntityObject Entity { get; set; }
}
注意,如果您不希望转换器负责填充实体对象,您仍然可以使用转换器的想法。在这种情况下,请ReadJson
方法在请求中设置EntityIdentifier
属性。但是,由于您已将此属性设为私有,因此您需要使用反射来执行此操作,将该属性设置为public,或者为请求创建一个构造函数,转换器可以使用该构造函数来使用标识符对其进行实例化。