当试图反序列化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; }
}
}
答案 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; }
}
}