【问题标题】:Object cannot by deserialized, because 'Collection was of a fixed size.'对象无法反序列化,因为“集合的大小是固定的。”
【发布时间】:2013-10-22 07:34:36
【问题描述】:

我有我真实代码的简单示例。我需要序列化为 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;
        }
    }

TestClass 的对象被序列化为有效的 JSON,但是当我尝试将其反序列化回对象时,NotSupportedException 会抛出消息 Collection is of a fixed size。

这是我的测试

    [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);
    }

【问题讨论】:

  • 为什么一定要用Array而不是List&lt;string&gt;
  • 因为我需要对类进行序列化和反序列化,这些类是存在的,而且不容易更改。重写所有类是最后的可能性。

标签: c# json serialization json.net


【解决方案1】:

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】:

    谢谢,它有效!在我的示例中,我修改了您的代码以获得更一般的用法。

    我想

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

      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);
          }
      }
      

    【讨论】:

      猜你喜欢
      • 2020-02-24
      • 1970-01-01
      • 2018-11-06
      • 1970-01-01
      • 2015-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多