Reputation: 93
I'm writing a parser for minecraft entity definitions. I find this convention in the data where an object like "rolls" might be defined this way
"rolls": {
"min": 2,
"max": 2
}
but also might be defined this way
"rolls": 1
I'm using Newtonsoft JSON.net in case anyone knows of a json.net way to do this. I'm just not sure if there is a simple way to represent this variation with c#
Upvotes: 1
Views: 194
Reputation: 93
This took a long time to fingure out, and this solution is probably non-optimal, but this code does work
class RollsConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Rolls));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Object)
{
return token.ToObject<Rolls>();
}
return new Rolls(token.ToObject<Int64>());
}
public override bool CanWrite
{
get { return true; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JToken t = JToken.FromObject(value);
Rolls rolls = value as Rolls;
if (rolls.Value > 0)
{
writer.WriteValue(rolls.Value);
}
else
{
JObject o = (JObject)t;
o.WriteTo(writer);
}
}
}
public class Rolls
{
public Rolls(Int64 val)
{
Value = val;
}
public static implicit operator Rolls(Int64 value)
{
return new Rolls(value);
}
public bool ShouldSerializeMin()
{
// Only is value is unspecified
return Value == 0;
}
public bool ShouldSerializeMax()
{
// Only is value is unspecified
return Value == 0;
}
public bool ShouldSerializeValue()
{
// Only is value is specified
return Value > 0;
}
[JsonProperty(PropertyName = "min", NullValueHandling = NullValueHandling.Ignore)]
public Int64 Min { get; set; }
[JsonProperty(PropertyName = "max", NullValueHandling = NullValueHandling.Ignore)]
public Int64 Max { get; set; }
[JsonIgnore]
public Int64 Value { get; set; }
}
[JsonProperty(PropertyName = "rolls", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(RollsConverter))]
public Rolls Roll { get; set; }
Upvotes: 0
Reputation: 960
I've used the c# type dynamic
for this purpose. It enables you to read the variables out of the object, as if it were strongly typed.
in your case..
dynamic myObj = //your JSON deserialize method
//first example (Take note of the array)
int min = myObj.rolls[0].min;
int max = myObj.rolls[0].max;
//your second example
int numRolls = myObj.rolls;
Note you'll get no code suggestion, but it does work at runtime, providing the JSON is deserialized correctly. It can help if you place a breakpoint over the dynamic myObj
line, so you can see exactly what the object is made up of.
I'm not sure on its memory usage / safe usability, perhaps someone could comment?
Note: This was for use in a data structure that was ever changing and out of my control, there would have been dozens upon dozens of classes to create and maintain. There's likely still a better way to do it, but if your example is the most complex structure you'll face, you're best to just create those two classes and deserialize to the correct one.
Upvotes: 2