【问题标题】:System.ArgumentOutOfRangeException while deserializing using Newtonsoft.Json使用 Newtonsoft.Json 反序列化时出现 System.ArgumentOutOfRangeException
【发布时间】:2016-12-22 02:01:47
【问题描述】:

我正在使用 Newtonsoft JSON 反序列化包含接口的对象。 Newtonsoft 在“弄清楚”如何在反序列化时将接口映射到它们的具体类型时遇到了麻烦,所以我按照this answer 中的指示来解决这个问题。

我正在做以下反序列化:

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)

只是为了使反序列化工作?

【问题讨论】:

  • 我要做的第一件事就是从等式中去掉 XML。看起来您应该能够提供一个 minimal reproducible example 而不需要任何 XML。
  • @JonSkeet 你的意思是来自我的帖子还是来自我的解决方案? (现在无论好坏,我都必须使用 XML 作为解决方案本身的一部分)。
  • 仅从您的帖子中找出问题。解决软件问题主要是删除不相关的方面,直到您只看到一个有问题的部分。
  • 我同意,XML 本身似乎不是这里的问题。我完全包含它的主要原因是我用来获取反序列化的类型信息,尽管当我单步执行代码时,我可以看到它正在解析我正在寻找的类型,所以我怀疑这可能也不是问题。
  • 对。因此,请提供一个minimal reproducible example,它会尽可能简单地重现问题。

标签: c# json json.net deserialization json-deserialization


【解决方案1】:

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 值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    相关资源
    最近更新 更多