是否可以以不同方式序列化对象以使用Json.Net对其进行反序列化?

时间:2014-08-04 12:12:30

标签: c# serialization json.net

以下是我的例子:

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; }

}

这就是我真正希望实现的目标,但据我所知,唯一可以实际将这类代码放在自定义转换器中的地方,但不幸的是,我似乎无法做到确定转换器在使用时是用于序列化还是反序列化。

4 个答案:

答案 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,或者为请求创建一个构造函数,转换器可以使用该构造函数来使用标识符对其进行实例化。