我有一个简单的实例代码示例。我需要序列化为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 抛出消息集合具有固定大小。
这是我的测试
[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);
}
答案 0 :(得分:6)
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());
答案 1 :(得分:1)
谢谢,它有效!我修改了您的代码,以便在我的示例中更常用。
我想
序列化参数与构造函数参数同名(忽略大小写)
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);
}
}