首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么Newtonsoft反序列化器不对智能getter反序列化?

为什么Newtonsoft反序列化器不对智能getter反序列化?
EN

Stack Overflow用户
提问于 2020-01-30 16:41:47
回答 1查看 445关注 0票数 5

上下文

我有两门课:

  • LiteralModel是字符串值属性的包装器。
  • 表达式有一个字符串名和一个名为LiteralModel的文本。

公共类ExpressionModel {私有字符串名称;公共字符串名称{获取=>名称?"";设置=>名称=值;}私有LiteralModel文字;公共LiteralModel文字{获取=>文字?新LiteralModel();设置=>文字=值;}公共类LiteralModel {私有字符串值;公共字符串值{获取=>值?“;设置=> this.value =值;}

所有这些都是带有公共getter和setter的公共属性,因此我希望它们都能轻松地序列化和反序列化,即使使用空保护,而且大多数情况下都是这样。

问题

ExpressionModel的文字属性不能正确反序列化。下面是一个演示这个问题的最小测试:

代码语言:javascript
运行
复制
    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看起来很像我想要的/expect(包装字符串"61"),但是当我将它反序列化回一个ExpressionModel时,文字测试失败了--它得到一个空字符串的LiteralModel。

我试过的

如果我删除表达式模型的文字getter的智能性,它的行为就像预期的那样--所有测试都通过了。但是,智能属性确实可以处理字符串属性。那么为什么不在我的LiteralModel对象上呢?

更奇怪的是,如果我将空检查移到setter而不是getter,那么所有的测试都会通过:

代码语言:javascript
运行
复制
        public LiteralModel Literal
        {
            get => literal;
            set => literal = value ?? new LiteralModel();
        }

结论

简而言之,没有任何东西会分阶段序列化,智能设置器也很好,但是除了string之外,智能getter会中断反序列化。

这似乎是极端武断的行为。有人知道为什么会这样吗,或者是否有任何方法可以让这些类按照编写的方式工作呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-30 16:50:50

我怀疑问题在于Json.NET正在调用属性getter,然后调用结果的setter。例如,类似这样的东西--尽管很明显,通过反射:

代码语言:javascript
运行
复制
var expression = new ExpressionModel();
expression.Name = "test";
var literal = expression.Literal;
if (literal is null)
{
    // No literal - create one and set it
    literal = new LiteralModel();
    expression.Literal = literal;
}
// Now literal is non-null either way, so set the value.
literal.Value = "61";

按照代码的工作方式,您的Literal getter正在创建一个新的LiteralModel,但随后将其丢弃。撇开Json.NET不说,这仍然是相当令人困惑的。例如:

代码语言:javascript
运行
复制
var expression = new Expression();
expression.Literal.Value = "foo";
Console.WriteLine(expression.Literal.Value); // Empty string

您可以更改ExpressionModel代码,以便将新创建的LiteralModel分配给属性,如果它创建了一个:

代码语言:javascript
运行
复制
public LiteralModel Literal
{
    get => literal ?? (literal = new LiteralModel());
    set => literal = value;
}

这将避免“简单代码”行为如此令人困惑--而且我希望它也能修复Json.NET行为。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59990623

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档