反序列化使用TypeNameHandling.All序列化的字符串

使用以下样本序列化了一个类

using Newtonsoft.Json; using System; namespace ConsoleAppCompare { class Program { static void Main(string[] args) { Movie movie = new Movie() { Name = "Avengers", Language = "En", Actors = new Character[] { new Character(){Name="Phil Coulson"},new Character(){Name="Tony Stark"} }}; Console.WriteLine(JsonConvert.SerializeObject(movie, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All })); Console.ReadLine(); } } class Movie { public string Name { get; set; } public string Language { get; set; } public Character[] Actors { get; set; } } class Character { public string Name { get; set; } } } 

上面的示例生成以下json

 { "$type": "ConsoleAppCompare.Movie, ConsoleAppCompare", "Name": "Avengers", "Language": "En", "Actors": { "$type": "ConsoleAppCompare.Character[], ConsoleAppCompare", "$values": [ { "$type": "ConsoleAppCompare.Character, ConsoleAppCompare", "Name": "Phil Coulson" }, { "$type": "ConsoleAppCompare.Character, ConsoleAppCompare", "Name": "Tony Stark" } ] } } 

现在,在另一个无法访问上述模型的程序中,
我必须将字符串反序列化为一个对象,但我尝试过的任何东西似乎都在工作……

为了创建我的新模型,我在剪贴板上复制了json并使用了Visual Studio的“Paste Special”function

 using Newtonsoft.Json; using System; using System.IO; namespace ConsoleAppCompare { class Program { static void Main(string[] args) { var s = File.ReadAllText(@"C:\Users\nvovo\Desktop\asdf\aa.txt"); Rootobject movie = null; // nothing Works :( //movie =JsonConvert.DeserializeObject(s, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }); //movie = JsonConvert.DeserializeObject(s, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None }); //movie = JsonConvert.DeserializeObject(s); Console.ReadLine(); } } public class Rootobject { public string type { get; set; } public string Name { get; set; } public string Language { get; set; } public Actors Actors { get; set; } } public class Actors { public string type { get; set; } public Values[] values { get; set; } } public class Values { public string type { get; set; } public string Name { get; set; } } } 

我可以对此做些什么,或者我应该尝试找到原来的课程吗?

更新

我不关心“$ type”属性。 它甚至不在原始型号上。 我只想将JSON反序列化为强类型模型,包括集合(我的实际类具有更多嵌套级别),但自动生成的类型(使用Paste Json)不起作用。

如果您只想忽略类型信息,那么:

  • 如果使用TypeNameHandling.None反序列化,则简单地忽略对象上的"$type"属性将导致反序列化期间没有问题。

  • 但即使使用TypeNameHandling.None集合值的 "$type"属性也会导致问题,因为为集合生成的类型元数据会强制在JSON中强制嵌套:

    "type"

     { "Actors": { "$type": "ConsoleAppCompare.Character[], ConsoleAppCompare", "$values": [] } } 

    没有:

     { "Actors": [] } 

    使用TypeNameHandling.None反序列化JSON时,如果遇到具有额外嵌套级别的序列化集合,则会引发exception。

    因此,您需要一些方法来在反序列化期间去除额外的嵌套级别,例如使用自定义JsonConverter 。 在对于在版本/格式之间迁移序列化Json.NET文档的策略的 回答中 ,有一个已经编写并可供使用: IgnoreCollectionTypeConverter

因此,您可以按如下方式定义模型:

 public class Rootobject { public string Name { get; set; } public string Language { get; set; } public List Actors { get; set; } } public class Actor { public string Name { get; set; } } 

并反序列化如下:

 var settings = new JsonSerializerSettings { Converters = { new IgnoreCollectionTypeConverter() }, }; var movie = JsonConvert.DeserializeObject(s, settings); 

样品小提琴 。

笔记:

  • IgnoreCollectionTypeConverter用于处理读/写集合,这就是我将Actors从数组更改为List

  • 如果您需要处理类型信息而不是忽略它,则需要创建自定义ISerializationBinder 。 有关详细信息,请参阅Custom SerializationBinder 。 如何为二进制格式化程序创建SerializationBinder,以处理从一个程序集和名称空间到另一个程序集和名称空间的类型移动,这为创建处理generics嵌套的自定义序列化活页夹提供了解决方案。

更新

你问, 我只是想将json反序列化为强类型模型,包括集合(我的真实类有更多的嵌套级别)但是自动生成的类型(使用Paste Json)不起作用。

在开发过程中,您可以使用LINQ to JSON将JSON加载到内存中,删除所有"$type"元数据,并写出新的JSON字符串。 然后,您可以获取该已清理的字符串并将其用于“将Json粘贴为类”。

以下扩展方法将执行必要的工作:

 public static class JsonExtensions { const string valuesName = "$values"; const string typeName = "$type"; public static JToken RemoveTypeMetadata(this JToken root) { if (root == null) throw new ArgumentNullException(); var types = root.SelectTokens(".." + typeName).Select(v => (JProperty)v.Parent).ToList(); foreach (var typeProperty in types) { var parent = (JObject)typeProperty.Parent; typeProperty.Remove(); var valueProperty = parent.Property(valuesName); if (valueProperty != null && parent.Count == 1) { // Bubble the $values collection up removing the synthetic container object. var value = valueProperty.Value; if (parent == root) { root = value; } // Remove the $values property, detach the value, then replace it in the parent's parent. valueProperty.Remove(); valueProperty.Value = null; if (parent.Parent != null) { parent.Replace(value); } } } return root; } } 

示例工作.Net小提琴 ,它接受您的输入JSON字符串并返回:

 { "Name": "Avengers", "Language": "En", "Actors": [ { "Name": "Phil Coulson" }, { "Name": "Tony Stark" } ] }