使用以下示例
序列化了一个类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"功能
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<Rootobject>(s, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
//movie = JsonConvert.DeserializeObject<Rootobject>(s, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None });
//movie = JsonConvert.DeserializeObject<Rootobject>(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; }
}
}
我可以对此做些什么,或者我应该尝试找到原来的课程吗?
更新
我不在乎&#34; $ type&#34;属性。它甚至不在原始型号上。我只想将JSON反序列化为强类型模型,包括集合(我的真实类具有更多嵌套级别),但自动生成的类型(使用Paste Json)不起作用。
答案 0 :(得分:2)
如果您只想忽略类型信息,那么:
如果您使用TypeNameHandling.None
进行反序列化,那么对象上的"$type"
属性将被忽略,在反序列化过程中不会出现任何问题。
但即使使用TypeNameHandling.None
,集合值的"$type"
属性也会导致问题,因为为集合生成的类型元数据会强制在JSON中增加嵌套级别:
使用"type"
:
{
"Actors": {
"$type": "ConsoleAppCompare.Character[], ConsoleAppCompare",
"$values": []
}
}
没有:
{
"Actors": []
}
使用TypeNameHandling.None
反序列化JSON时,如果遇到具有额外嵌套级别的序列化集合,则会抛出异常。
因此,您需要某种方法在反序列化期间去除额外的嵌套级别,例如用custom JsonConverter
。在问题this answer的Strategies for migrating serialized Json.NET document between versions/formats中,有一个已经编写并可供使用:IgnoreCollectionTypeConverter
。
因此,您可以按如下方式定义模型:
public class Rootobject
{
public string Name { get; set; }
public string Language { get; set; }
public List<Actor> Actors { get; set; }
}
public class Actor
{
public string Name { get; set; }
}
反序列化如下:
var settings = new JsonSerializerSettings
{
Converters = { new IgnoreCollectionTypeConverter() },
};
var movie = JsonConvert.DeserializeObject<Rootobject>(s, settings);
示例fiddle。
注意:
IgnoreCollectionTypeConverter
旨在使用读/写集合,这就是我将Actors
从数组更改为List<T>
的原因。
如果您需要处理类型信息而不是忽略它,则需要创建自定义ISerializationBinder
。有关详细信息,请参阅Custom SerializationBinder。问题How to create a SerializationBinder for the Binary Formatter that handles the moving of types from one assembly and namespace to another提供了一个解决方案,用于创建处理泛型嵌套的自定义序列化绑定器。
更新
你问,我只是想将json反序列化为强类型模型,包括集合(我的真实类有更多嵌套级别)但是自动生成的类型(使用Paste Json)不起作用。< / em>的
在开发过程中,您可以使用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 fiddle,它接受您输入的JSON字符串并返回:
{
"Name": "Avengers",
"Language": "En",
"Actors": [
{
"Name": "Phil Coulson"
},
{
"Name": "Tony Stark"
}
]
}