2016-08-15 172 views
2

我正在使用Newtonsoft JSON反序列化包含接口的对象。 Newtonsoft在解析如何将接口映射到具体的反序列化类型时遇到了困难,所以我按照this answer中的说明修复了这个问题。使用Newtonsoft.Json反序列化时System.ArgumentOutOfRangeException

我做下面的反序列化:

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: 

顺便说一下,我尝试调用反序列化的行中会出现这种情况。

编辑:整个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。看起来你应该能够提供没有任何XML的[mcve]。 –

+0

@JonSkeet你的意思是来自我的文章还是来自我的解决方案? (现在好或坏我必须使用XML作为解决方案本身的一部分)。 – EJoshuaS

+1

从您的帖子,以隔离问题。解决软件问题主要是删除不相关的方面,直到你只能看到一个有问题的位。 –

回答

2

Version尚未以正确的方式序列化。

如果做得正确,应该魔神像这样:

{ 
    ... 
    "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

相关问题