Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
527 views
in Technique[技术] by (71.8m points)

c# - Set accessor not being called when I deserialise object from Json.net

public class SpecialObject
{
    public string ID;
    [JsonIgnore]
    public List<SpecialObject> SpecialObjectCollection = new List<SpecialObject>();
    [JsonIgnore]
    public List<string> tempObjectIDs = new List<string>();

    [JsonProperty]
    public List<string> SpecialObjectIDs { get { return SpecialObjectCollection.Select(x => x.ID).ToList(); } set { tempObjectIDs = value; } }

    public SpecialObject() { }
    public SpecialObject(string _id) { ID = _id; }
}

static void Main(string[] args)
{
    SpecialObject parent = new SpecialObject("parentIDstring");
    parent.SpecialObjectCollection.Add(new SpecialObject("childIDstring"));

    string test = JsonConvert.SerializeObject(parent);
    SpecialObject reconstructedObject = JsonConvert.DeserializeObject<SpecialObject>(test);
}

//string test:
//{"ID":"parentIDstring","SpecialObjectIDs":["childIDstring"]}

I want to serialise SpecialObject to JSON and back again. The "SpecialObjectIDs" accessor lets me avoid nasty circular references and helps me reconstruct the complex relational network since I only need the unique IDs.

It serialises just fine, but I need to deserialise the objects; when I do so, my array (SpecialObjectIDs in JSON) just disappears during the conversion, the set accessor doesnt seem to be called.

How do I get the Newtonsoft.Json (JSON.net) library to put the deserialised List in tempObjectIDs but keep the existing get behavior?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your problem is that, when deserializing a collection that is not read-only, Json.NET checks to see if the collection has already been allocated, for instance in the constructor of the containing type. If so, it fills the pre-existing collection for the deserialized JSON contents, and never sets the collection back. Unfortunately, your property returns a temporary proxy collection, so your container class SpecialObject never receives the deserialized results.

The simplest way to prevent this is to specify that Json.NET should always allocate a new collection and set it back rather than reuse the pre-existing collection, via the JsonPropertyAttribute setting ObjectCreationHandling = ObjectCreationHandling.Replace

[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> SpecialObjectIDs { get { return SpecialObjectCollection.Select(x => x.ID).ToList(); } set { tempObjectIDs = value; } }

Alternatively you could use a string [] rather than a List<string> for your proxy collection property:

public string [] SpecialObjectIDs { get { return SpecialObjectCollection.Select(x => x.ID).ToArray(); } set { tempObjectIDs = value == null ? null : value.ToList(); } }

As arrays cannot be resized, Json.NET will always allocate a new array when deserializing and set it back when complete.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...