将Json反序列化为具体类

时间:2018-02-02 20:46:24

标签: c# json json-deserialization

当试图反序列化Json时,我无法找到解决错误的方法:

  

'无法创建ConsoleApp1.IDisplayInstructions类型的实例。 Type是接口或抽象类,无法实例化。路径' displayInstructions.AGB',第4行,第34位。'

我理解它背后的意义;我需要指示Json反序列化器使用哪个具体类作为接口成员。我只是不知道该怎么做。我尝试使用JsonConstructor属性,或使用自定义反序列化器 - 但我无法使任何一种方法工作。

还有一个类似的问题(JSON.NET - how to deserialize collection of interface-instances?),但这是一个接口的字段,而不是类本身。

using Newtonsoft.Json;
using System.Collections.Generic;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string jsonData = @"{
    'Term' : 'john'
   ,'resourceTypes' : ['POL', 'CLM', 'WRK']
   ,'displayInstructions': {'AGB':{'DisplayAttributes':['AssuredName','PolicyNumber','DistributorName','EffectiveDate'],'Format':'|resource_type| (|rank|) {0} / {1}'}
            ,'AGT':{'DisplayAttributes':['AssuredName','PolicyNumber','DistributorName','EffectiveDate'],'Format':'|resource_type| (|rank|) {0} / {1}'}
            ,'AGY':{'DisplayAttributes':['AssuredName','PolicyNumber','DistributorName','EffectiveDate'],'Format':'|resource_type| (|rank|) {0} / {1}'}
            ,'CLM':{'DisplayAttributes':['AssuredName','PolicyNumber','DistributorName','EffectiveDate'],'Format':'|resource_type| (|rank|) {0} / {1}'}
            ,'PLU':{'DisplayAttributes':['AssuredName','PolicyNumber','DistributorName','EffectiveDate'],'Format':'|resource_type| (|rank|) {0} / {1} / {2}'}
            ,'POL':{'DisplayAttributes':['AssuredName','PolicyNumber','DistributorName','EffectiveDate'],'Format':'|resource_type| (|rank|) {0} / {1} / {2}'}
            ,'PRV':{'DisplayAttributes':['AssuredName','PolicyNumber','DistributorName','EffectiveDate'],'Format':'|resource_type| (|rank|) {0} / {1}'}}

}";

            SearchCriteria sc = Newtonsoft.Json.JsonConvert.DeserializeObject<SearchCriteria>(jsonData);
        }
    }

    interface ISearchCriteria
    {
        string Term { get; set; }
        IEnumerable<string> ResourceTypes { get; set; }
        IDisplayInstructions DisplayInstructions { get; set; }
    }

    class SearchCriteria : ISearchCriteria
    {
        public string Term { get; set; }
        public IEnumerable<string> ResourceTypes { get; set; }

        public IDisplayInstructions DisplayInstructions
        {
            get { return this.displayInstructions as IDisplayInstructions; }
            set
            {
                this.displayInstructions = new DisplayInstructions();
                foreach (var kvp in value)
                {
                    this.displayInstructions.Add(kvp.Key, kvp.Value);
                }
            }
        }

        private DisplayInstructions displayInstructions;

        [JsonConstructor]
        public SearchCriteria(string term, IEnumerable<string> resourceTypes, IDisplayInstructions displayInstructions)
        {
            this.Term = term;
            this.ResourceTypes = resourceTypes;
            this.DisplayInstructions = displayInstructions;
        }
    }

    interface IDisplayInstructions : IDictionary<string, IDisplayInstruction> { }

    class DisplayInstructions : Dictionary<string, IDisplayInstruction> { }

    interface IDisplayInstruction
    {
        IEnumerable<string> DisplayAttributes { get; set; }
        string Format { get; set; }
    }

    class DisplayInstruction : IDisplayInstruction
    {
        public IEnumerable<string> DisplayAttributes { get; set; }
        public string Format { get; set; }
    }
}

1 个答案:

答案 0 :(得分:0)

Matthew Groves(JSON.NET - how to deserialize collection of interface-instances)上面提供的帖子有一半答案,另一半来自JsonDictionary属性(Applying JsonDictionary attribute to dictionary)。我能够保持接口方法,因为它符合我所追求的单元测试方法。

最终代码:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string jsonData = @"{
    'Term' : 'john'
   ,'resourceTypes' : ['POL', 'CLM', 'WRK']
   ,'displayInstructions': {'AGB' : {'displayAttributes' : ['AssuredName','PolicyNumber','DistributorName','EffectiveDate'] ,'format':'|resource_type| (|rank|) {0} / {1}'}
                           ,'POL' : {'displayAttributes' : ['AssuredName','PolicyNumber','DistributorName','EffectiveDate'] ,'format':'|resource_type| (|rank|) {0} / {1}'}}
}";

            SearchCriteria des = JsonConvert.DeserializeObject<SearchCriteria>(jsonData);
        }
    }

    interface ISearchCriteria
    {
        string Term { get; set; }
        IEnumerable<string> ResourceTypes { get; set; }
        IDisplayInstructions DisplayInstructions { get; set; }
    }

    public class ConfigConverter<I, T> : JsonConverter
    {
        public override bool CanWrite => false;
        public override bool CanRead => true;
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(I);
        }
        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)
        {
            var jsonObject = JObject.Load(reader);
            var deserialized = (T)Activator.CreateInstance(typeof(T));
            serializer.Populate(jsonObject.CreateReader(), deserialized);
            return deserialized;
        }
    }

    class SearchCriteria : ISearchCriteria
    {
        public string Term { get; set; }
        public IEnumerable<string> ResourceTypes { get; set; }

        [JsonConverter(typeof(ConfigConverter<IDisplayInstructions, DisplayInstructions>))]
        public IDisplayInstructions DisplayInstructions { get; set; }
    }

    interface IDisplayInstructions : IDictionary<string, IDisplayInstruction> { }

    [JsonDictionary(ItemConverterType = typeof(ConfigConverter<IDisplayInstruction, DisplayInstruction>))]
    class DisplayInstructions : Dictionary<string, IDisplayInstruction>, IDisplayInstructions
    {

    }

    interface IDisplayInstruction
    {
        IEnumerable<string> DisplayAttributes { get; set; }
        string Format { get; set; }
    }

    [JsonConverter(typeof(ConfigConverter<IDisplayInstruction, DisplayInstruction>))]
    class DisplayInstruction : IDisplayInstruction
    {
        public IEnumerable<string> DisplayAttributes { get; set; }
        public string Format { get; set; }
    }
}