Reputation: 1795
I am wondering if there is a way to set default value for a property in relation to other property of the same class in Json.NET e.g like this:
public class JsonsoftExample
{
[JsonProperty(Required = Required.Always)]
public DateTime Start { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue(Start.AddHours(1))]
public DateTime End { get; set; }
}
What I am trying to accomplish here is to populate End with DateTime value that is one hour later than Start in cases e.g when deserializing json to domain model and End value is missing or null. Like this:
string json = "{\"Start\": \"2017-01-01T08:00:00+01:00\"}";
var deserialized = JsonConvert.DeserializeObject<JsonsoftExample>(json);
The way I am doing it now is just inspecting later in code if End value is null in my domain object and if it is - populating it with desired value.
Is it feasible the way proposed in code sample or is there maybe a better simpler way except for the manual checking as in paragraph above?
Upvotes: 1
Views: 4767
Reputation: 116980
As specified in the JSON standard, a JSON object is an unordered set of name/value pairs, so in general Json.NET does not allow one property to be set relative to another. Json.NET is a streaming, single-pass deserializer and there's no guarantee which will appear first in the JSON.
However, when your object specifies use of a parameterized constructor via, e.g., the [JsonConstructor]
attribute, Json.NET will pre-load the JSON properties and their values then construct the object with the deserialized values. This affords an opportunity to set the End
property relative to the Start
property:
public partial class JsonsoftExample
{
public JsonsoftExample() { }
[JsonConstructor]
JsonsoftExample(DateTime start, DateTime? end)
{
this.Start = start;
this.End = end ?? Start.AddHours(1);
}
[JsonProperty(Required = Required.Always)]
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
Notes:
The names of the constructor arguments must be the same as the names of the properties, modulo case. This is how Json.NET matches constructor arguments with JSON properties.
Note that the End
property is of type DateTime
while the end
constructor argument is of type DateTime?
. When "End"
is missing from the JSON, Json.NET will pass in a null
value into the constructor, which can be checked for to properly initialize the End
time relative to the Start
.
If you don't want to serialize the End
property when it is exactly one hour later than the start, you can use conditional property serialization:
public bool ShouldSerializeEnd()
{
return End != Start.AddHours(1);
}
The constructor does not need to be public when marked with [JsonConstructor]
. Properties not passed into the constructor will be populated after construction as per usual deserialization.
Sample fiddle.
Upvotes: 1
Reputation: 77896
If you are using C# 6 then probably you can do like [* Not sure if this is what you are looking to achieve]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public DateTime End { get; set; } = Start.AddHours(1);
Upvotes: 1