Yet another answer based on existing one.
The tiny problem with @rasx approach is that when the serialized type contains a field of another compound type that doesn't implement the interface, you get an exception.
The reason is that the CreateProperties is called for each serialized type, including the actual serialized object type and the types of all its properties.
A workaround is to check if the type examined in the CreateProperties is in fact a type implementing the interface or any other type.
public class InterfaceContractResolver<TInterface> : DefaultContractResolver where TInterface : class
{
protected override IList<JsonProperty> CreateProperties( Type type, MemberSerialization memberSerialization )
{
if ( typeof( TInterface ).IsAssignableFrom( type ) )
{
IList<JsonProperty> properties = base.CreateProperties(typeof(TInterface), memberSerialization);
return properties;
}
else
{
return base.CreateProperties( type, memberSerialization );
}
}
}
Take a look at previously failing example that works now:
public interface IFoo
{
string Bar { get; set; }
Child Child { get; set; }
}
// this is the serialized type, it implements the interface
public class Foo : IFoo
{
public string Bar { get; set; }
public string Qux { get; set; }
public Child Child { get; set; }
}
// this is a child type, doesn't implement the interface
public class Child
{
public string Name { get; set; }
}
This works now
var foo = new Foo()
{
Bar = "bar",
Qux = "qux",
Child = new Child()
{
Name = "child"
}
};
// To serialize do this:
var settings = new JsonSerializerSettings()
{
ContractResolver = new InterfaceContractResolver<IFoo>()
};
var s_foo = JsonConvert.SerializeObject(foo, settings);
var s_full = JsonConvert.SerializeObject(foo);
var foo_full = JsonConvert.DeserializeObject<Foo>(s_full);
var foo_foo = JsonConvert.DeserializeObject<Foo>(s_full, settings);
Console.WriteLine( foo_full );
Console.WriteLine( foo_foo );