【问题标题】:DeserializeObject not working with object typeDeserializeObject 不适用于对象类型
【发布时间】:2017-03-29 15:04:37
【问题描述】:

我的序列化和反序列化有问题。 下面的代码在序列化时将 List 对象记录作为列表,但是在反序列化时它不起作用。

每个标签参数都是对象类型

TreeViewCollection = new ObservableCollection<TreeViewItem>()
        {
            new TreeViewItem()
            {
                Header = "Suite 1"
            },
            new TreeViewItem()
            {
                Header = "Suite 2",
                Nodes = new ObservableCollection<TreeViewItem>()
                {
                    new TreeViewItem()
                    {
                        Header = "Case 1"
                    }
                }
            },
            new TreeViewItem()
            {
                Header = "Suite 2",
                Nodes = new ObservableCollection<TreeViewItem>()
                {
                    new TreeViewItem()
                    {
                        Header = "Case 2",
                        Tag = new List<ListViewItem>()
                        {
                            new ListViewItem()
                            {
                                Tag = new ActionObject()
                                {
                                    Command = "Command",
                                    Target = "Target",
                                    Value = "Value",
                                    Comment = "Comment"
                                }
                            }
                        }
                    },
                    new TreeViewItem()
                    {
                        Header = "Case 3"
                    }
                }
            }
        };

        string serializedJson = JsonConvert.SerializeObject(TreeViewCollection, Formatting.Indented, new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.Objects,
            TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple
        });

        var deserializedObject = JsonConvert.DeserializeObject<ObservableCollection<TreeViewItem>>(serializedJson, new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.Objects,
            TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple
        });

        TreeViewCollection = deserializedObject;

但是它以 JSON 形式出现,而不是 List() 对象

{[
  {
    "$type": "RFA.Models.Items.ListViewItem, RFA",
    "ID": "0b9661f0-87f1-41f4-85cb-620dc1f49bb3",
    "Name": null,
    "Tag": {
      "$type": "RFA.Models.Objects.ActionObject, RFA",
      "Command": "Command",
      "Target": "Target",
      "Value": "Value",
      "Comment": "Comment"
    }
  }
]}

如何让 json 反序列化以处理对象类型

请求的 TreeviewItem 类:

public partial class TreeViewItem
{
    #region Private Variables

    private string _header;
    private object _tag;
    private ObservableCollection<TreeViewItem> _nodes;

    #endregion
    #region Properties

    public string Header
    {
        get { return _header; }
        set
        {
            if (value == _header) return;
            _header = value;
            OnPropertyChanged();
        }
    }
    public object Tag
    {
        get { return _tag; }
        set
        {
            if (value == _tag) return;
            _tag = value;
            OnPropertyChanged();
        }
    }
    public ObservableCollection<TreeViewItem> Nodes
    {
        get { return _nodes; }
        set
        {
            if (Equals(value, _nodes)) return;
            _nodes = value;
            OnPropertyChanged();
        }
    }
    #endregion
}

【问题讨论】:

  • 1) 可以分享TreeViewItem 类型,或者简化版吗?没有minimal reproducible example 就很难知道您的问题。是System.Windows.Controls.TreeViewItem吗? 2) 你能通过但它以 JSON 而非 List() 对象 的形式出现吗?
  • 我提供了 Treeviewitem 类,这个类是 system.windows.controls.TreeViewItem 的“副本”。不,我不能使用原来的课程。当我反序列化 JSON 字符串时,而不是将其解析为 List 对象。相反,如果保留为 json 字符串。没有抛出错误,但它与我的代码混淆,因为我的代码需要一个列表。

标签: c# json serialization deserialization


【解决方案1】:

您的问题是您将new List&lt;ListViewItem&gt;() 值分配给object Tag 属性,然后使用TypeNameHandling = TypeNameHandling.Objects 进行序列化和反序列化。正如Newtonsoft docs 中所解释的,此枚举具有以下含义:

None      0   Do not include the .NET type name when serializing types.
Objects   1   Include the .NET type name when serializing into a JSON object structure.
Arrays    2   Include the .NET type name when serializing into a JSON array structure.
All       3   Always include the .NET type name when serializing.
Auto      4   Include the .NET type name when the type of the object being serialized is not the same as its declared type. Note that this doesn't include the root serialized object by default. To include the root object's type name in JSON you must specify a root type object with SerializeObject(Object, Type, JsonSerializerSettings) or Serialize(JsonWriter, Object, Type).

通过使用TypeNameHandling.Objects,您可以省略List&lt;ListViewItem&gt; 集合的类型信息,因此,在序列化和反序列化时,您的Tag 会变成一个LINQ-to-JSON JArray

相反,我建议使用TypeNameHandling.Auto。这仅在必要时包括类型信息 - 即,当属性值或集合项的声明类型与实际观察到的类型不匹配时。使用它会导致为您的 object Tag 属性发出类型信息,但不会为您的完全类型化的 ObservableCollection&lt;TreeViewItem&gt; Nodes 属性发出类型信息。

或者,如果您可以将 Newtonsoft 属性添加到您的模型,您可以使用[JsonProperty(TypeNameHandling = TypeNameHandling.All)] 标记Tag 属性:

[JsonProperty(TypeNameHandling = TypeNameHandling.All)]
public object Tag { get; set; }

如果您无条件地需要对象的类型信息,即使不需要反序列化并且无法将 Newtonsoft 属性添加到您的模型中,您可以使用 TypeNameHandling.All - 但我真的不推荐此设置,因为它无条件地发出类型信息即使在没有必要的时候也收集。例如,如果您决定将集合的类型从List&lt;T&gt; 更改为ObservableCollection&lt;T&gt;,这可能会导致问题。如果这样做,您需要在反序列化期间使用IgnoreCollectionTypeConverter 之类的内容去除集合类型信息,如this answer 所示。 (可惜TypeNameHandling.Auto | TypeNameHandling.Objects好像没有实现。)

最后,在使用TypeNameHandling 时,请注意Newtonsoft docs 的注意事项:

当您的应用程序从外部源反序列化 JSON 时,应谨慎使用 TypeNameHandling。使用 None 以外的值反序列化时,应使用自定义 SerializationBinder 验证传入类型。

关于为什么这可能是必要的讨论,请参阅TypeNameHandling caution in Newtonsoft Json

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2016-04-07
    • 1970-01-01
    • 2021-07-24
    • 1970-01-01
    • 2018-11-17
    相关资源
    最近更新 更多