如何使用构造函数反序列化readonly结构,该构造函数将readonly结构作为in参数?

时间:2018-05-12 01:52:14

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

我有一个readonly struct(Outer),它有一个readonly结构属性(Inner),它作为in参数传递给构造函数,以避免在调用构造函数时出现一个副本。尝试反序列化外部导致Json.Net被in参数混淆:

using System;
using Newtonsoft.Json;

namespace DeserializeTest
{
    public readonly struct Inner
    {
        [JsonConstructor]
        public Inner(int i) => I = i;

        public int I { get; }
    }

    public readonly struct Outer
    {
        [JsonConstructor]
        public Outer(in Inner inner) => Inner = inner;

        public Inner Inner { get; }
    }

    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Environment version: " + Environment.Version);
            Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
            Console.WriteLine();

            try
            {
                var originalOuter = new Outer(new Inner(1));
                var json = JsonConvert.SerializeObject(originalOuter);
                var newOuter = JsonConvert.DeserializeObject<Outer>(json);
                Assert.IsTrue(originalOuter.Inner.I == newOuter.Inner.I);
                Console.WriteLine(json);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with unhandled exception: ");
                Console.WriteLine(ex);
                throw;
            }
        }
    }

    public class AssertionFailedException : Exception
    {
        public AssertionFailedException(string s) : base(s) { }
    }

    public static class Assert
    {
        public static void IsTrue(bool value)
        {
            if (!value)
            {
                throw new AssertionFailedException("failed");
            }
        }
    }
}

这导致了这个输出:

Environment version: 4.0.30319.42000
Json.NET version: Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed

Unhandled Exception: Newtonsoft.Json.JsonSerializationException: Unable to find a constructor to use for type DeserializeTest.Inner&. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'Inner.I', line 1, position 14.
   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.ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, 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.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at DeserializeTest.Program.Main() in e:\projects\DeserializeTest\DeserializeTest\Program.cs:line 31

0 个答案:

没有答案