using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.ComponentModel;
using System.Globalization;
using System.Collections.Specialized;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Runtime.Serialization.Formatters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace Question42537050
public class ExampleClass1
public string Foo { get; set; }
internal static void Test()
new PropertyValue(new ExampleClass1 { Foo = "hello" }) { PropertyName = "name1", ToolTip = "tip1" },
new PropertyValue(DateTime.Today.ToUniversalTime()) { PropertyName = "name2", ToolTip = "tip2" },
new PropertyValue(3.14m) { PropertyName = "name3", ToolTip = "tip3" },
new PropertyValue(3.14) { PropertyName = "name4", ToolTip = "tip4" },
new PropertyValue(10101) { PropertyName = "name5", ToolTip = "tip5" },
new PropertyValue((long)10101) { PropertyName = "name6", ToolTip = "tip6" },
var json = JsonConvert.SerializeObject(list, Formatting.Indented);
var list2 = JsonConvert.DeserializeObject<PropertyValue[]>(json);
var json2 = JsonConvert.SerializeObject(list2, Formatting.Indented);
Console.WriteLine(json2);
Assert.IsTrue(list.Length == list2.Length && list.Select(p => p.CurrentValue.GetType()).SequenceEqual(list2.Select(p => p.CurrentValue.GetType())));
public class AssertionFailedException : System.Exception
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
public static class Assert
public static void IsTrue(bool value)
throw new AssertionFailedException("failed");
[JsonConverter(typeof(PropertyValueConverter))]
public sealed class PropertyValue
public PropertyValue(object CurrentValue)
SetCurrentValue(CurrentValue);
public string PropertyName { get; set; }
public string CategoryName { get; set; }
public string DisplayName { get; set; }
public int PropertyId { get; set; }
public string TypeName { get; set; }
public string ToolTip { get; set; }
public string Description { get; set; }
public object CurrentValue { get; set; }
public void SetCurrentValue(object value)
TypeName = value.GetType().AssemblyQualifiedName;
public class PropertyValueConverter : JsonConverter
public override bool CanConvert(Type objectType)
return typeof(PropertyValue).IsAssignableFrom(objectType);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
if (reader.TokenType == JsonToken.Null)
var propertyValue = (existingValue as PropertyValue ?? new PropertyValue());
var obj = JObject.Load(reader);
var jValue = obj.GetValue("CurrentValue", StringComparison.OrdinalIgnoreCase).RemoveFromLowestPossibleParent();
serializer.Populate(obj.CreateReader(), propertyValue);
if (!string.IsNullOrEmpty(propertyValue.TypeName) && jValue != null)
string typeName, assemblyName;
ReflectionUtils.SplitFullyQualifiedTypeName(propertyValue.TypeName, out typeName, out assemblyName);
var type = serializer.Binder.BindToType(assemblyName, typeName);
propertyValue.SetCurrentValue(jValue.ToObject(type, serializer));
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
throw new NotImplementedException();
public static class JsonExtensions
public static JToken RemoveFromLowestPossibleParent(this JToken node)
var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
if (node.Parent is JProperty)
((JProperty)node.Parent).Value = null;
public static class ReflectionUtils
public static void SplitFullyQualifiedTypeName(string fullyQualifiedTypeName, out string typeName, out string assemblyName)
int? assemblyDelimiterIndex = GetAssemblyDelimiterIndex(fullyQualifiedTypeName);
if (assemblyDelimiterIndex != null)
typeName = fullyQualifiedTypeName.Substring(0, assemblyDelimiterIndex.GetValueOrDefault()).Trim();
assemblyName = fullyQualifiedTypeName.Substring(assemblyDelimiterIndex.GetValueOrDefault() + 1, fullyQualifiedTypeName.Length - assemblyDelimiterIndex.GetValueOrDefault() - 1).Trim();
typeName = fullyQualifiedTypeName;
private static int? GetAssemblyDelimiterIndex(string fullyQualifiedTypeName)
for (int i = 0; i < fullyQualifiedTypeName.Length; i++)
char current = fullyQualifiedTypeName[i];
public static void Main()
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);