【问题标题】:Why field isn't set during json deserialization?为什么在 json 反序列化期间未设置字段?
【发布时间】:2020-11-05 13:05:27
【问题描述】:

我有一个如下所示的序列化对象:

{
  "Var4": "value set in Foo()",
  "var3": "value set in NestedFoo()",
  "<var3>k__OriginalField": "value set in NestedFoo()",
  "<Var4>k__BackingField": "value set in Foo()"
}

来自这个对象:

public class DummyClass 
    {
        [ModificationTrackerAspect]
        public string var3 = "initialValue";
        public string Var4 { get; set; } = "initialValue";
        
    }

在 var3 上有一个继承自 Postsharp 方面LocationInterceptionAspect 的属性。 此方面的副作用是将受影响的字段更改为属性并为此属性创建支持字段(该字段为"&lt;var3&gt;k__OriginalField"

在序列化过程中一切似乎都很好,但由于我想反序列化它,我无法设置 var3 字段/属性。

反序列化是这样发生的:

instanceTypeName = ... (fetched from a text file);
unknowclassDeserialized = JsonConvert.DeserializeObject(json, Type.GetType(instanceTypeName));

我尝试将调试器中的 json 更改为:

{
  "Var4": "value set in Foo()",
  "var3": "value set in NestedFoo()",
  "<Var4>k__BackingField": "value set in Foo()"
}

{
  "Var4": "value set in Foo()",
  "Var3": "value set in NestedFoo()",
  "<var3>k__OriginalField": "value set in NestedFoo()",
  "<Var4>k__BackingField": "value set in Foo()"
}

最后:

{
  "Var4": "value set in Foo()",
  "Var3": "value set in NestedFoo()",
  "<Var4>k__BackingField": "value set in Foo()"
}

但我总是得到一个正确设置 var4 并将 var3 设置为其初始值的对象。 我做错了什么?

编辑:在 postsharp 文档中说:

请注意,当向字段添加 LocationInterceptionAspect 时,该字段将替换为具有相同字段和可见性的属性。该字段本身已重命名并设为私有。

编辑 2:为了清楚起见,我删除了静态变量并更改了反序列化以反映我的真实意图。

【问题讨论】:

  • var3 不是属性而是变量,变量没有后备字段。像这样声明public string var3 { get; set; }
  • @RandRandom 我不想更改 var3,这是一个更大项目的一部分,我不想将每个字段都更改为属性。是的 var3 在编译时成为属性,因为 Postsharp 请参阅有关 locationInterceptionAspect => doc.postsharp.net/location-interception 的链接
  • 来自链接的引用:请注意,当向字段添加 LocationInterceptionAspect 时,该字段将替换为相同字段和可见性的属性。该字段本身已重命名并设为私有。
  • C# 区分大小写,您的 json 具有 Var3,但您的类已将其定义为 var3,在这两种情况下都可以选择 Vv
  • @RandRandom 就像我在帖子中所说的那样,我尝试了两种语法。看看我发布的 4 个 JSON。

标签: c# json serialization json.net postsharp


【解决方案1】:

在我看来,您的问题是您的财产名称中有非法字符。我建议使用 JsonProperty 注释和一个子构造函数。重要的是,松散静态,因为这个内存地址将被这个类的每个实例重新使用,使其像“单例”一样的值,怀疑这是你的意图

public class DummyClass 
{
    [JsonProperty("Var3")]  
    private string var1 = "initialValue";
    [JsonProperty("Var4")]
    private string Var2 = "initialValue";

    [ModificationTrackerAspect]
    [JsonIgnore]
    public string Var3 =>var1 ;

    [JsonIgnore]
    public string Var4 { get=>Var2 ; set=> Var2=value; } 
        
}

【讨论】:

  • 我不确定您所说的“属性名称中的非法字符”是什么意思,因为我只使用 [a-zA-Z] 字符。而且我并没有真正了解您对静态变量所做的事情,但这些是真实变量,我知道静态变量意味着什么。为清楚起见,我将删除它们,因为它与我的问题无关。我也不能使用属性,因为直到运行时我才知道要反序列化什么类。由于配置文件,属性 (ModificationTrackerAspect) 在编译时通过 postsharp 添加。
  • 我编辑了我的问题,很抱歉写得不清楚。
  • @Jirochan,“k__OriginalField”不会映射
【解决方案2】:

罪魁祸首是 PostSharp 在其添加的属性上发出的 [CompilerGenerated] 属性。

默认情况下,默认合同解析器会忽略所有具有这些属性的字段/属性。您需要通过在DefaultContractResolver 上设置SerializeCompilerGeneratedMembers 来覆盖此行为,即:

JsonConvert.SerializeObject(
    before, 
    new JsonSerializerSettings() 
    { 
        ContractResolver = new DefaultContractResolver() 
        { 
            SerializeCompilerGeneratedMembers = true 
        } 
    })

如果您已经序列化了数据,您可能需要编写自己的自定义解析器以提供正确的映射。

【讨论】:

  • 嗨,谢谢,但目前我已经修改了合约解析器,并且它已经序列化了所有内容。它在反序列化时失败。当你说我需要编写一个自定义解析器来提供正确的映射时,你的意思是编写一个反序列化器,或者覆盖 JSON.NET 的一些属性/方法?
  • 您需要确保反序列化也获取 JsonProperty 表示从 json 到 var3 属性的映射值。将相同的 ContractResolver 传递给 DeserializeObject 应该会有所帮助。
猜你喜欢
  • 1970-01-01
  • 2020-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-11
  • 2021-11-01
相关资源
最近更新 更多