DeserializeObject不使用对象类型

时间:2017-03-29 15:04:37

标签: c# json serialization deserialization

我在序列化和反序列化时遇到问题。 下面的代码在序列化时将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 个答案:

答案 0 :(得分:2)

您的问题是,您要为new List<ListViewItem>()属性分配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<ListViewItem>集合的类型信息,因此,在序列化和反序列化时,您的Tag会变成LINQ-to-JSON {{1 }}

相反,我建议使用JArray。这仅包括必要时的类型信息 - 即,当声明的属性值或集合项的类型与实际的观察类型不匹配时。使用此选项将导致为TypeNameHandling.Auto属性发出类型信息,但不会为您的object Tag属性进行完全输入。

或者,如果您可以将Newtonsoft属性添加到模型中,则可以使用[JsonProperty(TypeNameHandling = TypeNameHandling.All)]标记ObservableCollection<TreeViewItem> Nodes属性:

Tag

如果您无条件地要求对象的类型信息,即使不需要反序列化也无法将Newtonsoft属性添加到模型中,您可以使用[JsonProperty(TypeNameHandling = TypeNameHandling.All)] public object Tag { get; set; } - 但我并不是真的推荐此设置,因为它无条件即使没有必要,也会为集合发出类型信息。例如,如果您决定将集合的类型从TypeNameHandling.All更改为List<T>,则可能会出现问题。如果这样做,您需要在反序列化过程中使用ObservableCollection<T>之类的内容删除集合类型信息,如this answer所示。 (遗憾的是,IgnoreCollectionTypeConverter似乎没有实施。)

最后,在使用TypeNameHandling.Auto | TypeNameHandling.Objects时,请注意Newtonsoft docs中的这一注意事项:

  

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

有关可能需要执行此操作的讨论,请参阅 TypeNameHandling caution in Newtonsoft Json

相关问题