using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public class StartingFunds
public double Value { get; set; }
[JsonConverter(typeof(DifficultyConverter))]
public int CombatModifier { get; set; }
public string Name { get; set; }
public StartingFunds StartingFunds { get; set; }
public List<string> Dwarves { get; set; }
public List<Difficulty> Difficulty { get; set; }
public static IEnumerable<Difficulty> EnumerateDifficulties()
return Enumerable.Range(1, 10).Select(i => new Difficulty { CombatModifier = i });
public class DifficultyConverter : JsonConverter
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
throw new NotImplementedException();
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
var token = JToken.Load(reader);
return Library.EnumerateDifficulties().FirstOrDefault(d => d.CombatModifier == intv);
return token.DefaultToObject(objectType, serializer);
throw new JsonSerializationException(string.Format("Unknown token {0}", token.Type));
public override bool CanWrite => false;
public override bool CanConvert(Type objectType) => objectType == typeof(Difficulty);
public static partial class JsonExtensions
public static object DefaultToObject(this JToken token, Type type, JsonSerializer serializer = null)
var oldParent = token.Parent;
var dtoToken = new JObject(new JProperty(nameof(DefaultSerializationDTO<object>.Value), token));
var dtoType = typeof(DefaultSerializationDTO<>).MakeGenericType(type);
var dto = (IHasValue)(serializer ?? JsonSerializer.CreateDefault()).Deserialize(dtoToken.CreateReader(), dtoType);
token.RemoveFromLowestPossibleParent();
return dto == null ? null : dto.GetValue();
public static JToken RemoveFromLowestPossibleParent(this JToken node)
var contained = node.Parent is JProperty ? node.Parent : node;
if (contained is JProperty)
((JProperty)node.Parent).Value = null;
[JsonObject(NamingStrategyType = typeof(Newtonsoft.Json.Serialization.DefaultNamingStrategy), IsReference = false)]
class DefaultSerializationDTO<T> : IHasValue
public DefaultSerializationDTO(T value) { this.Value = value; }
public DefaultSerializationDTO() { }
[JsonConverter(typeof(NoConverter)), JsonProperty(ReferenceLoopHandling = ReferenceLoopHandling.Serialize)]
public T Value { get; set; }
object IHasValue.GetValue() { return Value; }
public class NoConverter : JsonConverter
public override bool CanConvert(Type objectType) { throw new NotImplementedException(); }
public override bool CanRead { get { return false; } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); }
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); }
public static void Test()
var settings = new JsonSerializerSettings
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
var root = JsonConvert.DeserializeObject<RootObject>(json, settings);
var json2 = JsonConvert.SerializeObject(root, Formatting.Indented, settings);
Console.WriteLine(json2);
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];