代码之家  ›  专栏  ›  技术社区  ›  Dmitry Streblechenko

Json。Net:填充接口属性时指定对象类型

  •  0
  • Dmitry Streblechenko  · 技术社区  · 8 年前

    我有一个对象,它实现了一个接口,该接口的属性是另一个接口:

    public interface IMaster
    {
       ISlave ObjectProp {get; set; }
    }
    
    public interface ISlave 
    {
       string Name {get; set; }
    }
    ...
    public class Master : IMaster
    {
       public ISlave ObjectProp {get; set; }
    }
    public class Slave : ISlave
    {
       public string Name {get; set; }
    }
    

    我可以创建Master类的一个实例,并使用 JsonConvert.PopulateObject .
    然而,当反序列化属性时,解析器显然无法创建接口的实例。

    有没有办法告诉Json库(通过属性、回调等)创建从属类的实例(实现相关接口)?

    1 回复  |  直到 8 年前
        1
  •  1
  •   Dmitry Streblechenko    8 年前

    是的,这看起来像是复制品- JsonConverterAttribute 看起来效果不错。为完整起见,以下是解决方案:

    ...
    public class Master : IMaster
    {
       [JsonConverter(typeof(ModelJsonConverter), typeof(Slave))]
       public ISlave ObjectProp {get; set; }
    }
    ...
    public class ModelJsonConverter : JsonConverter
        {
            public Type InstanceType { get; set; }
            public ModelJsonConverter(Type instanceType):base()
            {
                InstanceType = instanceType;
            }
    
            public override bool CanWrite => false;
            public override bool CanRead => true;
            public override bool CanConvert(Type objectType)
            {
                if (objectType == InstanceType) return true;
                else return InstanceType.GetTypeInfo().Is​Subclass​Of(objectType);
            }
    
            public override void WriteJson(JsonWriter writer,
                                           object value, JsonSerializer serializer)
            {
                throw new InvalidOperationException("Use default serialization.");
            }
    
            public override object ReadJson(JsonReader reader,
                                            Type objectType, object existingValue,
                                            JsonSerializer serializer)
            {
                if (reader.TokenType == JsonToken.Null) return null;
                else if (reader.TokenType != JsonToken.StartObject) throw new JsonException($"Unexpected Json token at {reader.Path}: {reader.TokenType.ToString()}");
                var deserialized = Activator.CreateInstance(InstanceType);
                serializer.Populate(reader, deserialized);
                return deserialized;
            }
    
        }