I have public class Result
and object created from it:
public static readonly Result NotStarted = new Result(1, "", nameof(NotStarted));
This is realization of this pattern. In my case Result is based on TypesafeEnumBase:
public class TypesafeEnumBase : ITypesafeEnum
{
[DefaultValue(typeof(string), "")]
[JsonProperty("text", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
public virtual string Description { get; protected set; }
[DefaultValue(typeof(int), "1")]
[JsonProperty("code", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
public virtual int Id { get; protected set; }
[DefaultValue(typeof(string), "")]
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
public virtual string Name { get; protected set; }
}
Now I'm receiving json object serialized from type containing Result property
[DataContract, Serializable]
public class IOResultBase : IIOResult
{
[XmlIgnore]
[JsonProperty("Result", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
public virtual Result Result { get; set; }
public IOResultBase()
{
this.Result = Result.NotStarted;
}
}
You may notice that there is default value in constructor equals to Result.NotStarted
static class.
I get json like this {"Result":{"text":"","code":0,"name":"Success"}}
As you notice it has code of 0. And now IOResultBase foo = JsonConvert.DeserializeObject<IOResultBase>(json)
is pushing this code 0 into foo.
But it turns out that 0 is being pushed in public static readonly Result NotStarted
itself (even despite its readonly) instead of just creating new instance of foo.Result. So now 'code' of NotStarted (which is actually globally used constant) is changed from 1 to 0.
How should I force DeserializeObject to create new instance of public class Result
instead of overriding public static readonly Result NotStarted
?
CodePudding user response:
Pay utmost attention to the default (de)serialization settings of Newtonsoft.Json. Quite a few will not be what many would intuitvely expect them to be.
Such as, if there is an existing object instance in a property like the Result.NotStarted
instance in the IOResultBase.Result
property, Newtonsoft.Json will try to reuse the existing object instance provided by the property, meaning populating this existing instance with the values from the json.
Specifially, to solve your problem, you will have to set Newtonsoft.Json's setting ObjectCreationHandling
to ObjectCreationHandling.Replace
. So, perhaps something along the lines of:
var foo = JsonConvert.DeserializeObject<IOResultBase>(
json,
new JsonSerializerSettings() { ObjectCreationHandling = ObjectCreationHandling.Replace }
);