我有一个包含多行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);
但是在上面从动态反序列化返回的o
对象中,似乎无法访问$type
字段名。
我想我可以用文本解析每一行,寻找$type
,但这似乎也很混乱。
在序列化时使用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:tempQ37034748.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