简体   繁体   English

是否可以使用Json.Net以不同于序列化的方式序列化对象?

[英]Is it possible to serialize an object differently to deserializing it using Json.Net?

Here is my example: 这是我的示例:

JSON request string: JSON请求字符串:

{
    entity: '09f7cb28-0464-41c8-a20d-1b05eb1cda0a'
}

My request object: 我的请求对象:

public class Request {

    public Request() { }

    [JsonProperty("entity")]
    private string EntityIdentifier { get; set; }

    public EntityObject Entity { get; set; }

}

I've got this to work so that the string is passed to the EntityIdentifier, which is fine, then in my code I find the actual entity using the entity identifier property, populate the Entity property with the found entity but then this is what I get when I serialize the object: 我已经做到这一点,以便将字符串传递给EntityIdentifier,这很好,然后在我的代码中,我使用实体标识符属性找到了实际的实体,并使用找到的实体填充了Entity属性,但这就是我所要做的当我序列化对象时得到:

{
    entity: '09f7cb28-0464-41c8-a20d-1b05eb1cda0a',
    Entity: {
        // my object's properties
    }
}

When all I really want is: 我真正想要的是:

{
    entity: {
        // my object's properties
    }
}

Now, I know I could split this out into two different classes, and I may have to, but if there is a way to keep it all in the same class, it would be awesome and save me a lot of coding time. 现在,我知道我可以将其分为两个不同的类,也许必须这样做,但是如果有一种方法可以将它们全部保留在同一个类中,那将会很棒,并且可以节省很多编码时间。

To clarify because I seem to not be explaining what I want very well: 需要澄清,因为我似乎没有很好地解释我想要的东西:

Disclaimer: This doesn't exist (AFAIK) but this is what I would like: 免责声明:这不存在(AFAIK),但这是我想要的:

public class Request {

    public Request() { }

    [JsonProperty("entity", OnlyWhen=Deserializing)]
    private string EntityIdentifier { get; set; }

    [JsonProperty("entity", OnlyWhen=Serializing)]
    public EntityObject Entity { get; set; }

}

This is what I would really like to achieve, but as far as I can see the only place I could realistically put this type of code is in a custom converter, but unfortunately, I can't seem to be able to determine whether the converter is being used for serialization or deserialization when it is being used. 这是我真正想要实现的目标,但是据我所知,我可以将这种类型的代码实际放在唯一的位置是自定义转换器,但是不幸的是,我似乎无法确定转换器是否使用序列号时将其用于序列化或反序列化。

I believe you just need to mark Entity with [ScriptIgnore] and/or [JsonIgnore], like this: 我相信您只需要用[ScriptIgnore]和/或[JsonIgnore]标记Entity,如下所示:

[ScriptIgnore]
[JsonIgnore]
public EntityObject Entity { get; set; }

I have heard of JsonIgnore not working sometimes. 我听说JsonIgnore有时无法正常工作。 Using both is probably your best bet. 最好同时使用两者。

Also - I believe your wording is incorrect when describing the problem. 另外-我认为您在描述问题时的措辞不正确。 You state: "this is what I get when I deserialize the object" - when in fact, I believe you mean to say "serialize". 您声明:“这是我对对象进行反序列化时得到的”-实际上,我相信您的意思是说“序列化”。

If you need to populate Entity when EntityIdentifier is set, then replace the code for EntityIdentifier with something like: 如果在设置EntityIdentifier时需要填充Entity,则将EntityIdentifier的代码替换为以下内容:

string _eId;
[JsonProperty("entity")]
    private string EntityIdentifier 
    { 
        get{return _eId;}
        set
        {
            _eId = value;
            Entity = someMethodToRetrieveTheEntityById(_eId);
        }
    }

How about using the JsonIgnore attribute? 如何使用JsonIgnore属性?

    public class Request
    {

        public Request() { }

        [JsonIgnore]
        private string EntityIdentifier { get; set; }

        [JsonProperty("entity")]
        public EntityObject Entity { get; set; }

    }

The problem here could be that you're trying to force one class do the job of two. 这里的问题可能是您试图迫使一堂课做两堂课。 Why not do: 为什么不这样做:

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

Then you deserialize requests into EntityRequest objects, load EntityData objects using the EntityRequest and some other logic, then serialize the EntityData objects to file. 然后,您将请求反序列化为EntityRequest对象,使用EntityRequest和其他逻辑加载EntityData对象,然后将EntityData对象序列化为file。 The JsonProperty attributes here mean that both the request and the output entity are both called 'entity' just like in your OP. 这里的JsonProperty属性意味着请求和输出实体都被称为“实体”,就像在OP中一样。 This seems to be the workflow you're after. 这似乎是您要遵循的工作流程。

Cramming everything into one class is making this problem more complicated than it needs to be. 将所有事物塞到一类中会使这个问题变得更加复杂。

You can solve this problem with a custom JsonConverter similar to this: 您可以使用类似于以下内容的自定义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);
    }
}

To use the converter, simply decorate your Request class with a [JsonConverter] attribute as shown below. 要使用转换器,只需使用[JsonConverter]属性装饰您的Request类,如下所示。 Note that you can remove the private EntityIdentifier property, as it will no longer be needed. 请注意,您可以删除私有的EntityIdentifier属性,因为将不再需要它。 The converter has responsibility for retrieving the EntityObject from the database based on the identifier in the JSON. 转换器负责根据JSON中的标识符从数据库中检索EntityObject

[JsonConverter(typeof(RequestConverter))]
public class Request
{
    public Request() { }

    public EntityObject Entity { get; set; }
}

Note, if you don't want the converter to have responsibility for populating the entity object, you can still use the converter idea. 请注意,如果您不希望转换器负责填充实体对象,则仍然可以使用转换器思想。 In that case, make the ReadJson method set the EntityIdentifier property on the request. 在这种情况下,使ReadJson方法在请求上设置EntityIdentifier属性。 However, since you have made this property private, you will either need to use reflection to do this, make the property public, or make a constructor for the Request that the converter can use to instantiate it with the identifier. 但是,由于已将此属性设为私有,因此您将需要使用反射来做到这一点,将该属性设为公共,或者为Request创建一个构造函数,转换器可以使用该构造函数将该标识符实例化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM