How to deserialize Newtonsoft Json.NET references to separate, individual instances

前端 未结 2 1014
借酒劲吻你
借酒劲吻你 2021-01-13 05:59

I have a piece of JSON that looks like this:

[
  {
    \"$id\": \"1\",
    \"Name\": \"James\",
    \"BirthDate\": \"1983-03-08T00:00Z\",
    \"LastModified\         


        
2条回答
  •  孤街浪徒
    2021-01-13 06:50

    You could use a custom reference resolver. For example, assuming Name is the "primary key" for your objects, this should work. Of course, you may want to make it more generic.

    public class PersonReferenceResolver : IReferenceResolver
    {
        private readonly IDictionary _objects = 
            new Dictionary();
    
        public object ResolveReference(object context, string reference)
        {
            Person p;
            if (_objects.TryGetValue(reference, out p))
            {
                //This is the "clever" bit. Instead of returning the found object
                //we just return a copy of it.
                //May be better to clone your class here...
                return new Person
                {
                    Name = p.Name,
                    BirthDate = p.BirthDate,
                    LastModified = p.LastModified
                };
            }
    
            return null;
        }
    
        public string GetReference(object context, object value)
        {
            Person p = (Person)value;
            _objects[p.Name] = p;
    
            return p.Name;
        }
    
        public bool IsReferenced(object context, object value)
        {
            Person p = (Person)value;
    
            return _objects.ContainsKey(p.Name);
        }
    
        public void AddReference(object context, string reference, object value)
        {
            _objects[reference] = (Person)value;
        }
    }
    

    Now you deserialise like this:

    var jsonSerializerSettings = new JsonSerializerSettings()
    {
        ReferenceResolver = new PersonReferenceResolver()
    };
    
    var deserializedPersons = JsonConvert.DeserializeObject>(
        json, jsonSerializerSettings);
    

    Edit: I was bored so I made a generic version:

    public class GenericResolver : IReferenceResolver
        where TEntity : ICloneable, new()
    {
        private readonly IDictionary _objects = new Dictionary();
        private readonly Func _keyReader;
    
        public GenericResolver(Func keyReader)
        {
            _keyReader = keyReader;
        }
    
        public object ResolveReference(object context, string reference)
        {
            TEntity o;
            if (_objects.TryGetValue(reference, out o))
            {
                return o.Clone();
            }
    
            return null;
        }
    
        public string GetReference(object context, object value)
        {
            var o = (TEntity)value;
            var key = _keyReader(o);
            _objects[key] = o;
    
            return key;
        }
    
        public bool IsReferenced(object context, object value)
        {
            var o = (TEntity)value;
            return _objects.ContainsKey(_keyReader(o));
        }
    
        public void AddReference(object context, string reference, object value)
        {
            if(value is TEntity)
                _objects[reference] = (TEntity)value;
        }
    }
    

    With slightly new usage:

    var jsonSerializerSettings = new JsonSerializerSettings()
    {
        //Now we need to specify the type and how to get the object's key
        ReferenceResolver = new GenericResolver(p => p.Name)
    };
    
    var deserializedPersons = JsonConvert.DeserializeObject>(
        json, jsonSerializerSettings);
    

提交回复
热议问题