2016-08-15 3 views
2

Я использую Newtonsoft JSON для десериализации объекта, содержащего интерфейсы. У Newtonsoft возникли проблемы с «выяснением», как сопоставить интерфейсы с их конкретными типами при десериализации, поэтому я исправил проблему в this answer.System.ArgumentOutOfRangeException при десериализации с использованием Newtonsoft.Json

Я делаю следующее десериализовать:

var converter = new JsonSerializer(); 
converter.Converters.Add(new DeviceCalibrationConverter()); 

// Obviously parameter.value and typeObj being the JSON and Type respectively 
// I can see stepping through this that these are, in fact, the correct values 
object deserialized = converter.Deserialize(new StringReader(parameter.Value), typeObj); 

Я использую объект DeviceCalibrationConverter попытаться сопоставить мой интерфейс для его конкретного типа:

public class DeviceCalibrationConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     // I am trying to map the IDeviceCalibration interface to its concrete type (DeviceCalibration) 
     return objectType.Equals(typeof(IDeviceCalibration)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     return serializer.Deserialize(reader, typeof(DeviceCalibration)); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value); 
    } 
} 

В настоящее время я получаю "ArgumentOutOfRangeException." Полное описание исключения ниже:

System.ArgumentOutOfRangeException was unhandled 
    HResult=-2146233086 
    Message=Version's parameters must be greater than or equal to zero. 
Parameter name: build 
    Source=mscorlib 
    ParamName=build 
    StackTrace: 
     at System.Version..ctor(Int32 major, Int32 minor, Int32 build, Int32 revision) 
     at Void .ctor(Int32, Int32, Int32, Int32)(Object[]) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
     at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) 
     at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) 
     at Newtonsoft.Json.JsonSerializer.Deserialize(TextReader reader, Type objectType) 
     at FunctionalTesting.ExecuteXMLScript.Execute() in [folder]\ExecuteXMLScript.cs:line 141 
     at FunctionalTesting.TestRunner.RunTests() in [folder]\TestRunner.cs:line 102 
     at FunctionalTesting.Program.Main(String[] args) in [folder]\Program.cs:line 43 
     at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
     at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
     at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
     at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
     at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
     at System.Threading.ThreadHelper.ThreadStart() 
    InnerException: 

Это происходит, кстати, на линии, где я пытаюсь позвонить десериализации.

Edit: Весь JSON является довольно длительным, но оказывается, что виновный строка выглядит следующим образом:

{"State":"needs-translation","OriginalString":"LP","StringID":[id],"StringValue":"LP"}}], 
"MarketingFeatures":null, 
"CDIDriver" {"Name":"[Product Name]", 
"Version":{"Major":1,"Minor":0,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1}} 

В частности, в "Версии" десериализует к:

{"Major":1,"Minor":0,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1} 

Этот десериализуется класс System.Version, и это недействительно, таким образом, создавая исключение, указанное выше.

CDIDriver, кстати, создает объект Version следующим образом:

Version = new Version((int)major, (int)minor); 

Это вполне допустимо, и документ делает, на самом деле, сказать, что с помощью этого конструктора, как описано установит сборку и пересмотр до -1 (как показано в JSON). Тогда мой вопрос заключается в том, является ли это вполне допустимым, состояние документа объекта, почему оно создает это исключение, когда я пытаюсь десериализовать его?

Я знаю, что попытка сделать что-то вроде new Version(1, 0, -1, -1) приведет к исключению и что это документированное поведение. (Это похоже на очень странное поведение, учитывая, что это приведет к действительному состоянию объекта, но это только мое мнение). Есть ли какой-то способ:

new Version(1, 0, 0, 0) 

только ради проведения десериализации?

+2

Первое, что я хотел бы сделать, это избавиться от XML из уравнения. Похоже, вы должны быть в состоянии предоставить [mcve] без каких-либо XML вообще. –

+0

@JonSkeet Вы имеете в виду от моего поста или от моего решения? (Прямо сейчас, лучше или хуже, я должен использовать XML как часть самого решения). – EJoshuaS

+1

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

ответ

2

Version не был сериализован в правильном направлении.

Если все сделано правильно, он должен LOKE так:

{ 
    ... 
    "Version": "1.0" 
} 

Это может быть достигнуто путем использования VersionConverter так:

var json = JsonConvert.SerializeObject(new Version(1, 0), new VersionConverter()); 

Десериализация также использовать этот конвертер:

var obj = JsonConvert.DeserializeObject<Version>(json, new VersionConverter()); 

Рабочий пример: https://dotnetfiddle.net/eAqwip

Обратите внимание, что вы также можете аннотировать де/сериализованный класс с JsonConverterAttribute для достижения того же автоматически:

public class DeviceCalibration 
{ 
    ... 

    [JsonConverter(typeof(VersionConverter))] 
    public Version Version { get; set } 
} 

Если у вас нет доступа к коду сериализатора, боюсь, вам придется исправить строку Json «вручную» или написать свой собственный VersionConverter, который может обрабатывать значения -1.

+0

Спасибо, это отличное решение проблемы. – EJoshuaS

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