I'm using json.net to implement the memento pattern for a winform application. I'm using the memento to rollback an object on a failed database transaction. The problem I'm getting is that when deserializing the memento, the getter is called rather than the setter. Let me demonstrate:
class MyClass
{
public int ID { get; set; }
public string field1 { get; set; }
public string field2 { get; set; }
private List<SomeObject> _someObjects;
public List<SomeObject> SomeObjects
{
get
{
if(_someObjects == null)
{
_someObjects = LoadSomeObjectsFromDB();
}
return _someObjects;
}
set
{
_someObjects = value;
}
}
private List<AnotherObject> _anotherObjects;
public List<AnotherObject> AnotherObjects
{
get
{
if(_anotherObjects == null)
{
_anotherObjects= LoadAnotherObjectsFromDB();
}
return _anotherObjects ;
}
set
{
_anotherObjects = value;
}
}
}
*MyObject
, SomeObject
, and AnotherObject
extend the same base class, Model
As you can see from the sample class above, if SomeObjects is not loaded yet, it uses Lazy Loading to load it from the Database. Now When I serialize this object.
string memento = JsonConvert.SerializeObject(obj);
Resulting in
{
"ID": 1,
"field1": "field 1",
"field2": "field 2",
"SomeObjects": [
{
"ID": 1,
},
{
"ID": 2,
},
{
"ID": 3,
}
],
"AnotherObjects": [
{
"ID": 4,
},
{
"ID": 5,
},
{
"ID": 6,
}
]
}
Then subsequently deserialize it.
MyObject obj = JsonConvert.DeserializeObject(memento, typeof(MyObject));
I get an object represented by the following JSON
{
"ID": 1,
"field1": "field 1",
"field2": "field 2",
"SomeObjects": [
{
"ID": 1,
},
{
"ID": 2,
},
{
"ID": 3,
},
{
"ID": 1,
},
{
"ID": 2,
},
{
"ID": 3,
}
],
"AnotherObjects": [
{
"ID": 4,
},
{
"ID": 5,
},
{
"ID": 6,
},
{
"ID": 4,
},
{
"ID": 5,
},
{
"ID": 6,
}
]
}
Too many items in the SomeObjects
and AnotherObjects
List
s
SomeObjects
getter is called, which causes the List to initialize from the DB then the serialized list is Appended to it. Leaving me with more items in the list than desired. But if I remove the Lazy Loading portion
public List<SomeObject> SomeObjects
{
get
{
/*if(_someObjects == null)
{
_someObjects = LoadSomeObjectsFromDB();
}*/
return _someObjects;
}
set
{
_someObjects = value;
}
}
The getter is still called, but returns null. Then json.net calls the setter with value
being a list with the correct number of elements already added, whereas if the getter returns an initalized list, it appends to it never calling ths setter. Why the discrepancy, if a list is already initialized, the getter is called and it is appended to. But if not initialized, the setter is called and it is initialized with a list already filled with objects. Is there a way to make json.net only call the setter during deserialization of a generic List
?
JSON is a format that encodes objects in a string. Serialization means to convert an object into that string, and deserialization is its inverse operation (convert string -> object).
Json.NET has excellent support for serializing and deserializing collections of objects. To serialize a collection - a generic list, array, dictionary, or your own custom collection - simply call the serializer with the object you want to get JSON for.
NET objects (deserialize) A common way to deserialize JSON is to first create a class with properties and fields that represent one or more of the JSON properties. Then, to deserialize from a string or a file, call the JsonSerializer. Deserialize method.
Newtonsoft. Json uses reflection to get constructor parameters and then tries to find closest match by name of these constructor parameters to object's properties. It also checks type of property and parameters to match. If there is no match found, then default value will be passed to this parameterized constructor.
Json.Net has an ObjectCreationHandling
setting for this purpose. Try setting it to Replace
, e.g.:
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ObjectCreationHandling = ObjectCreationHandling.Replace;
MyObject obj = JsonConvert.DeserializeObject<MyObject>(memento, settings);
Demo: https://dotnetfiddle.net/rkY1pt
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With