2013-05-07 6 views
2

Я получаю «тип является интерфейсом, не может быть инстанциирован» Ошибка десериализации с Json.NET хотя я указать тип на объект Я пытаюсь десериализацииJson.net десериализации массив интерфейсов

private static JsonSerializerSettings settings = new JsonSerializerSettings { 
    TypeNameHandling = TypeNameHandling.Auto }; 

/// <summary> 
/// Returns an object created from the jObject and placed in a stub object 
/// </summary> 
/// <typeparam name="T"></typeparam> 
/// <param name="jObj"></param> 
/// <returns></returns> 
public static T FromJObject<T>(JToken jObj) 
{ 
    if (jObj == null) 
    { 
     jObj = new JObject(); 
    } 
    if (jObj is JValue) 
    { 
     return (T)((JValue)jObj).Value; 
    } 
    else 
    { 
     return (T)JsonConvert.DeserializeObject<T>(jObj.ToString(), settings); 
    } 
} 

это jObj

{ 
    "Id": 2, 
    "Name": "Name", 
    "JsonMapEnum": 0, 
    "Validations": [ 
    { 
     "Id": 1, 
     "$type": "JsonMap.Default.JValidation, JsonMap" 
    } 
    ], 
    "JSType": 3, 
    "SubJsonMapEnum": -1, 
    "$type": "JsonMap.Default.JAttribute, JsonMap" 
} 

Это ошибка

Could not create an instance of type JsonMap.Interfaces.IValidation. Type is an interface or abstract class and cannot be instantated. Path 'Validations[0].Id'

Похоже, он пытается превратить Id в объект Validation. Зачем?

этих интерфейсы, реализованных моих типами

public interface IJsonMap 
{ 
    long Id { get; set; } 
    String Name { get; set; } 
    LazyEnum JsonMapEnum { get; set; } 
} 

public interface IAttribute : IJsonMap 
{ 
    IEnumerable<IValidation> Validations { get; set; } 
    LazyEnum JSType { get; set; } 
    LazyEnum SubJsonMapEnum { get; set; } 
} 

public interface IValidation : IJsonMap 
{ 
    IEnumerable<IArgument> Arguments { get; set; } 
} 

это на вызов

FromJObject<JAttribute>(CreationJObj) 

JAttribute реализует IAttribute

ответ

2

По-видимому, «тип $» должен быть первым свойством в литерале строки, чтобы тип был пойман обработчиком типа. Я предполагаю, что это связано с тем, что десериализатор не проверяет существование типа $, он просто использует считыватель строки json, и, найдя первое свойство без установленного типа, он выходит из строя.

Вот метод, который я создал для обеспечения $ типа всегда первый

private static JToken ReorderJToken(this JToken jTok) 
    { 
     if (jTok is JArray) 
     { 
      var jArr = new JArray(); 
      foreach (var token in jTok as JArray) 
      { 
       jArr.Add(token.ReorderJToken()); 
      } 
      return jArr; 
     } 
     else if(jTok is JObject) 
     { 
      var jObj = new JObject(); 
      foreach(var prop in (jTok as JObject).Properties().OrderBy(x=> x.Name)) 
      { 
       prop.Value = prop.Value.ReorderJToken(); 
       jObj.Add(prop); 
      } 
      return jObj; 
     } 
     return jTok; 
    } 
+0

'По-видимому,« $ type »должно быть первым свойством». Нет необходимости в этом. Предположим, что вы являетесь автором сериализатора, вы бы использовали 'dict [" $ type "]' или 'list [0]' – I4V

+0

Хорошо, но у вас есть метод, который реорганизует ваши свойства, мне пришлось создать утилиту для именно по этой причине, и это никоим образом не было очевидным, что это было требованием. При работе с браузерами и созданием json на стороне клиента это не похоже на случай использования в левом поле. – DrSammyD

+0

Не поймите меня неправильно, я бесконечно благодарен JamesNK за ​​создание инструмента, все, что я говорю, это то, что это неожиданное поведение, извините за то, что я разочаровался в том, что я разочарован. – DrSammyD

0

Ну ясно, что она не может вывести соответствующий типа Основы аргументов, которые вы он кормит его. Без дополнительного контекста того, как это называется, я не могу сделать то, что у вас есть. Однако, если вы вызываете его с объектом, отличным от типа интерфейсов, он не будет работать. С определением вы должны всегда вызывать FromObject с T - это тип класса. Первое, что нужно сделать, это убедиться, что вы никогда не пытаетесь вызвать метод, где T равно typeof(IOneOfMyInterfaces), потому что это гарантированно провалится. Если это не исправить, я попробую назвать другую версию метода десериализации;

IMyInterface obj = (IMyInterface)serializer.Deserialize(validatingReader, t); 

Это работает, где validatingReader является JsonReader и t является Type объекта класса, реализующего IMyInterface. В настоящее время я использую его для общей десериализации с помощью json-схем для проверки правильности json.

+0

упс, извините, забыл включить это. JTransformer.FromJObject (CreationJObj) – DrSammyD

Смежные вопросы