代码之家  ›  专栏  ›  技术社区  ›  Rudis

无法反序列化对象,因为“集合的大小固定。”

  •  6
  • Rudis  · 技术社区  · 12 年前

    我有一个简单的真实代码示例。我需要序列化为JSON并反序列化类的对象 TestClass ,源自 Letters 。这两个类都有带参数的构造函数。

        public class TestClass : Letters
        {
            public string[] Names { get; private set; }
    
            public TestClass(string[] names)
                : base(names)
               // : base(new [] { "A", "B", })
               // : base(names.Select(a => a.Substring(0, 1)).ToArray())
            {
                Names = names;
            }
        }
    
        public abstract class Letters
        {
            public string[] FirstLetters { get; private set; }
    
            protected Letters(string[] letters)
            {
                FirstLetters = letters;
            }
        }
    

    的对象 测试类 被序列化为有效的JSON,但当我尝试将其反序列化回对象时, 冒号 与消息一起抛出 集合的大小是固定的。

    这是我的测试

        [Fact]
        public void JsonNamesTest()
        {
            var expected = new TestClass(new [] { "Alex", "Peter", "John", });
    
            var serialized = JsonConvert.SerializeObject(expected);
            Console.WriteLine(serialized);
    
            Assert.False(string.IsNullOrWhiteSpace(serialized));
    
            var actual = JsonConvert.DeserializeObject<TestClass>(serialized);
    
            AssertEx.PrimitivePropertiesEqual(expected, actual);
        }
    
    2 回复  |  直到 12 年前
        1
  •  6
  •   Brian Rogers    12 年前

    Json.Net需要所有类都有一个无参数构造函数来反序列化它们,否则它不知道如何调用构造函数。在不更改类的情况下解决此问题的一种方法是进行自定义 JsonConverter 它将从JSON创建对象实例。例如:

    class TestClassConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(TestClass) == objectType;
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject jo = JObject.Load(reader);
            string[] names = jo["Names"].ToObject<string[]>();
            return new TestClass(names);
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            serializer.Serialize(writer, value);
        }
    }
    

    然后,像这样反序列化您的类,它应该可以工作:

    var actual = JsonConvert.DeserializeObject<TestClass>(serialized, new TestClassConverter());
    
        2
  •  1
  •   Rudis    12 年前

    谢谢,它有效!我修改了您的代码,以便在我的示例中更通用。

    我想

    • 只有一个公共构造函数
    • 序列化参数与构造函数参数同名(忽略大小写)

      public class ParametersContructorConverter : JsonConverter
      {
          public override bool CanConvert(Type objectType)
          {
              return typeof(Letters).IsAssignableFrom(objectType);
          }
      
          public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
          {
              var jo = JObject.Load(reader);
              var contructor = objectType.GetConstructors().FirstOrDefault();
      
              if (contructor == null)
              {
                  return serializer.Deserialize(reader);
              }
      
              var parameters = contructor.GetParameters();
              var values = parameters.Select(p => jo.GetValue(p.Name, StringComparison.InvariantCultureIgnoreCase).ToObject(p.ParameterType)).ToArray();
      
              return contructor.Invoke(values);
          }
      
          public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
          {
              serializer.Serialize(writer, value);
          }
      }