我有一个包含多行json的文本文件,每行代表几种类型之一。例如,文件中的第一行可能表示序列化的Foo,而第二行表示序列化的Bar,依此类推。
问题是如何反序列化这些行? (反序列化要求您指定要使用的类型,但我事先并不知道每行代表哪种类型)
首先,我尝试在序列化程序上使用TypeNameHandling = TypeNameHandling.Objects
,它将字段名$type
嵌入到序列化的json中。这看起来很有希望我以为我可以将每一行作为动态对象读取,如下所示:
var o = JsonConvert.DeserializeObject<dynamic>(line_from_file);
然后提取出$type
字段,然后使用它来反序列化具体类,如下所示:
var concrete_object = JsonConvert.DeserializeObject<(type indicated in $type)>(line_from_file);
但$type
字段名称似乎无法在动态反序列化返回的o
对象中访问。
我想我可以对每一行进行文本解析,寻找$type
,但这看起来也很混乱。
答案 0 :(得分:3)
序列化时使用TypeNameHandling = TypeNameHandling.Objects
的重点是,您不必进行任何特殊处理以反序列化回特定类型。只要在反序列化时也指定TypeNameHandling = TypeNameHandling.Objects
,反序列化器将读取嵌入的$type
属性并为您实例化/填充正确的对象。 (请注意,DeserializeObject
为此目的具有非泛型重载,不需要指定Type参数;这可能是您混淆的原因。)
下面是一个往返演示程序来说明这一点。它将创建几个测试对象,按照问题中的描述将它们序列化为临时JSON文件,然后重新读入文件,将每行反序列化回一个对象并将其类型和内容转储到控制台。
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo { Id = 1, Name = "foo" };
Bar bar = new Bar { Length = 2.3, Width = 1.6 };
JsonSerializerSettings settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
Formatting = Formatting.None // ensure no line breaks in the JSON
};
string fileName = @"C:\temp\Q37034748.json";
// Write out sample file, one object per line
using (StreamWriter sw = new StreamWriter(fileName, false, Encoding.UTF8))
{
sw.WriteLine(JsonConvert.SerializeObject(foo, settings));
sw.WriteLine(JsonConvert.SerializeObject(bar, settings));
}
// Now read the file, deserializing each line to an object and dumping it out
using (StreamReader sr = new StreamReader(fileName, Encoding.UTF8))
{
while (!sr.EndOfStream)
{
object obj = JsonConvert.DeserializeObject(sr.ReadLine(), settings);
Dump(obj);
}
}
}
private static void Dump(object obj)
{
if (obj != null)
{
Type type = obj.GetType();
Console.WriteLine(type.FullName);
foreach (PropertyInfo prop in type.GetProperties())
{
Console.WriteLine(prop.Name + ": " + prop.GetValue(obj));
}
}
else
{
Console.WriteLine("null");
}
Console.WriteLine();
}
}
class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
class Bar
{
public double Length { get; set; }
public double Width { get; set; }
}
JSON文件看起来与此类似(您的命名空间/程序集名称可能不同):
{"$type":"JsonTest.Foo, JsonTest","Id":1,"Name":"foo"}
{"$type":"JsonTest.Bar, JsonTest","Length":2.3,"Width":1.6}
控制台输出如下所示:
JsonTest.Foo
Id: 1
Name: foo
JsonTest.Bar
Length: 2.3
Width: 1.6