using System.Collections;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public abstract class LikeType<T>
public T Value { get { return _value; } }
protected readonly Type Type;
private readonly T _value;
private readonly bool _isValueNull;
protected LikeType(T value, bool isNullAllowed = false)
_isValueNull = ReferenceEquals(value, null);
if (_isValueNull && !isNullAllowed)
throw new ArgumentNullException("value");
class LikeTypeConverter : JsonConverter
static Type GetValueType(Type objectType)
.Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(LikeType<>))
.Select(t => t.GetGenericArguments()[0])
public override bool CanConvert(Type objectType)
return GetValueType(objectType) != null;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
if (reader.SkipComments().TokenType == JsonToken.Null)
var valueType = GetValueType(objectType);
var value = serializer.Deserialize(reader, valueType);
return Activator.CreateInstance(objectType, value);
const string ValuePropertyName = "Value";
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType());
var valueProperty = contract.Properties.Single(p => p.UnderlyingName == ValuePropertyName);
serializer.Serialize(writer, valueProperty.ValueProvider.GetValue(value));
public static partial class JsonExtensions
public static JsonReader SkipComments(this JsonReader reader)
while (reader.TokenType == JsonToken.Comment && reader.Read())
public static class TypeExtensions
public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
public class CustomerId : LikeType<Guid>
public CustomerId(Guid value) : base(value) { }
public class EmailAddress : LikeType<string>
public EmailAddress(string value) : base(value) { }
public CustomerId Id { get; private set; }
public EmailAddress Email { get; private set; }
public Customer(CustomerId id, EmailAddress email)
public static void Test()
var desiredJson = @"{""id"": ""f5ce21a5-a0d1-4888-8d22-6f484794ac7c"",""email"": ""some@email.com""}";
var customer = new Customer(new CustomerId(new Guid("f5ce21a5-a0d1-4888-8d22-6f484794ac7c")), new EmailAddress("some@email.com"));
var settings = new JsonSerializerSettings
Converters = { new LikeTypeConverter() },
ContractResolver = new CamelCasePropertyNamesContractResolver()
var customerAsJson = JsonConvert.SerializeObject(customer, Formatting.Indented, settings);
Console.WriteLine("Serialized {0}:", customer);
Console.WriteLine(customerAsJson);
Assert.IsTrue(JToken.DeepEquals(JToken.Parse(customerAsJson), JToken.Parse(desiredJson)));
var customer2 = JsonConvert.DeserializeObject<Customer>(customerAsJson, settings);
Assert.IsTrue(customer.Email.Value == customer2.Email.Value && customer.Id.Value == customer2.Id.Value);
public static void Main()
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public class AssertionFailedException : System.Exception
public AssertionFailedException(string s) : base(s) { }
public static class Assert
public static void IsTrue(bool value)
public static void IsTrue(bool value, string message)
throw new AssertionFailedException(message ?? "failed");