Я написал собственный JsonConverter для обработки такого рода случая, в общем, учитывая, что исходный класс имеет интерфейс, перечисляющий, что нужно сериализовать.
Ваш интерфейс класса плюс сериализации:
public interface IUser {
Guid Id { get; set; }
string LoginName { get; set; }
...
}
public class User : IUser {
...implementation...
}
Конвертер:
public class InterfaceExtractorJsonConverter<T> : JsonConverter {
private class InterfaceDictionary<T> : Dictionary<string, object> { }
private PropertyInfo[] InterfaceProperties {
get { return typeof(T).GetProperties(); }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var dictionary = new InterfaceDictionary<T>();
foreach (var property in InterfaceProperties) {
dictionary[property.Name] = value.GetType().GetProperty(property.Name).GetValue(value, null);
}
serializer.Serialize(writer, dictionary);
}
private object ReadNestedObject(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
while (reader.TokenType == JsonToken.Comment) {
if (!reader.Read())
throw new Exception("Unexpected end.");
}
switch (reader.TokenType) {
case JsonToken.StartObject:
case JsonToken.StartArray:
return serializer.Deserialize(reader, objectType);
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Null:
case JsonToken.Undefined:
case JsonToken.Date:
case JsonToken.Bytes:
return reader.Value;
default:
throw new Exception(string.Format("Unexpected token when converting object: {0}", reader.TokenType));
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
var obj = Activator.CreateInstance(objectType);
while (reader.Read()) {
switch (reader.TokenType) {
case JsonToken.PropertyName:
string propertyName = reader.Value.ToString();
if (!reader.Read())
throw new Exception("Unexpected end.");
if (!InterfaceProperties.Any(p => p.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase))) {
reader.Skip();
continue;
}
var property = objectType.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var innerObj = ReadNestedObject(reader, property.PropertyType, existingValue, serializer);
property.SetValue(obj, innerObj, null);
break;
case JsonToken.Comment:
break;
case JsonToken.EndObject:
return obj;
}
}
throw new Exception("Unexpected end.");
}
public override bool CanConvert(Type objectType) {
return objectType.GetInterfaces().Contains(typeof(T));
}
}
Можно сделать много оптимизаций для конвертера ...