【发布时间】:2020-01-30 16:41:47
【问题描述】:
上下文
我有两个班级:
- LiteralModel 是字符串 Value 属性的包装器。
-
Expression 有一个字符串 Name 和一个名为 Literal 的 LiteralModel。
public class ExpressionModel { private string name; public string Name { get => name ?? ""; set => name = value; } private LiteralModel literal; public LiteralModel Literal { get => literal ?? new LiteralModel(); set => literal = value; } } public class LiteralModel { private string value; public string Value { get => value ?? ""; set => this.value = value; } }
所有都是具有公共 getter 和 setter 的公共属性,因此我希望它们都能够轻松地序列化和反序列化,即使使用 null 守卫,而且在大多数情况下,它们确实如此。
问题
ExpressionModel 的 Literal 属性未正确反序列化。以下是演示该问题的最小测试:
public void TestNewtonsoftExpressionDeserialization()
{
ExpressionModel expression = new ExpressionModel
{
Name = "test",
Literal = new LiteralModel { Value = "61" }
};
string json = JsonConvert.SerializeObject(expression);
Assert.IsTrue(json.Contains("61")); // passes
ExpressionModel sut = JsonConvert.DeserializeObject<ExpressionModel>(json);
Assert.AreEqual("test", sut.Name); // passes
Assert.AreEqual("61", sut.Literal.Value); // fails
}
如您所见,JSON 看起来如我所愿(包装字符串“61”),但是当我将其反序列化回 ExpressionModel 时,Literal 测试失败——它得到一个空字符串的 LiteralModel .
我的尝试
如果我删除了表达式模型的 Literal getter 的智能性,它的行为与预期一样——所有测试都通过了。但是智能属性确实作用于字符串属性。那么为什么不在我的 LiteralModel 对象上呢?
更奇怪的是,如果我将 null-check 移至 setter 而不是 getter,则所有测试都会通过:
public LiteralModel Literal
{
get => literal;
set => literal = value ?? new LiteralModel();
}
结论
简而言之,序列化器和智能设置器没有任何阶段,但智能获取器会破坏反序列化,string 除外。
这似乎是非常随意的行为。有谁知道为什么会这样,或者是否有任何方法可以让这些课程按书面形式工作?
【问题讨论】:
-
这和Why are all the collections in my POCO are null when deserializing some valid json with the .NET Newtonsoft.Json component的情况基本一样,和explanation一样:当getter返回非空值时,Json.NET反序列化后不调用setter。跨度>