CSharp · Console
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters;
using System.IO;
using System.Data;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
//https://stackoverflow.com/questions/49846209/deserialize-a-value-serialized-in-two-different-ways-with-json-net
[JsonConverter(typeof(ValuesConverter))]
public class Values
{
public int BestValue { get; set; }
public List<string> AllValues { get; set; }
}
internal class ValuesConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Values).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var tokenType = reader.SkipComments().TokenType;
if (tokenType == JsonToken.Null)
return null;
var value = existingValue as Values ?? (Values)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
if (tokenType == JsonToken.Date)
{
// Avoid annoying bug that converts date strings to local format described in
// https://stackoverflow.com/questions/35166060/json-net-get-specific-json-date-value
value.AllValues = new List<string> { JToken.Load(reader).ToString(Formatting.None).Trim('"') };
}
else if (tokenType.IsPrimitive())
{
value.AllValues = new List<string> { (string)JToken.Load(reader) };
}
else
{
serializer.Populate(reader, value);
}
return value;
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public static partial class JsonExtensions
{
public static JsonReader SkipComments(this JsonReader reader)
{
while (reader.TokenType == JsonToken.Comment && reader.Read())
;
return reader;
}
public static bool IsPrimitive(this JsonToken tokenType)
{
switch (tokenType)
{
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Undefined:
case JsonToken.Null:
case JsonToken.Date:
case JsonToken.Bytes:
return true;
default:
return false;
}
}
}
public class ValuesSubclass : Values
{
public string SomeOtherProperty { get; set; }
}
class TestClass
{
public static void Test()
{
var json = GetJson();
Console.WriteLine("Input JSON: ");
Console.WriteLine(json);
Test<Values>(json);
Test<ValuesSubclass>(json);
}
public static void Test<TValues>(string json) where TValues : Values
{
Console.WriteLine("\nTesting List<{0}>: ", typeof(TValues));
var list = JsonConvert.DeserializeObject<List<TValues>>(json);
var json2 = JsonConvert.SerializeObject(list, Formatting.Indented);
Console.WriteLine("Re-serialized JSON: ");
Console.WriteLine(json2);
Assert.IsTrue(list.Count == JArray.Parse(json).Where(t => t.Type != JTokenType.Comment).Count());
}
static string GetJson()
{
var json = @"[
""2009-02-15T00:00:00Z"" /* Make sure dates work */,
""MyFirstValue"" /* if only one value */,
// If multiple values
{ ""BestValue"" : 0, ""AllValues"" : [""DefaultValue"", ""OtherValue""] },
null /* check that null works */,
""c75d06a8-a705-48ec-b6b3-9076becf20f4"" /* Make sure GUIDs work */
]";
return json;
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine();
try
{
TestClass.Test();
}
catch (Exception ex)
{
Console.WriteLine("Failed with unhandled exception: ");
Console.WriteLine(ex);
throw;
}
}
}
public class AssertionFailedException : System.Exception
{
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
}
public static class Assert
{
public static void IsTrue(bool value)
{
IsTrue(value, "failed");
}
public static void IsTrue(bool value, string message)
{
if (value == false)
throw new AssertionFailedException(message ?? "failed");
}
}