如何将 JSON 反序列化为正确类型的对象,而无需事先定义类型? [英] How to deserialize JSON to objects of the correct type, without having to define the type before hand?

查看:21
本文介绍了如何将 JSON 反序列化为正确类型的对象,而无需事先定义类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我搜索了类似的问题,但没有找到与我要查找的内容完全匹配的内容.

C# 新手,请耐心等待.

我有一些要反序列化的 json 文件.我希望文件反序列化为正确类型的对象,而不必事先定义类型.这是我的代码:

公共类loadJson{//文件位置的路径public void readJson(字符串路径){//路径位置的文件数组.现在只读取一个文件FileInfo[] files = new DirectoryInfo(path).GetFiles("seleniumExample.json").ToArray();foreach(文件中的 FileInfo fi){动态 b1 = 空;使用 (StreamReader file = new StreamReader(fi.FullName)){string fileText = file.ReadToEnd();//Console.WriteLine(fileText);尝试{b1 = Newtonsoft.Json.JsonConvert.DeserializeObject(fileText);}捕获(例外 e){Console.WriteLine("错误!!!!" + e.ToString());}文件.关闭();}}}}

我有一堆对象类型,我将通过 json 文件将它们输入到我的程序中.

我不想显式地将 b1 称为投标、客户或任何其他特定的预定义类.如果我明确将 b1 称为 Bid,它会加载所有信息并填写正确的实例变量.

但是当我使用动态"或一般的对象"时,它无法弄清楚并且只是初始化为对象".

有没有办法执行通用反序列化并让它根据 json 文件中定义的字段创建正确类的对象?

在此先感谢您的帮助,如果我的问题非常不清楚,我深表歉意.如果是这样,请告诉我如何帮助澄清任何歧义.再次感谢.

解决方案

Json.NET 能够在序列化过程中记录多态类型的 .Net 对象类型,通过使用设置 TypeNameHandling = TypeNameHandling.Auto.启用该设置后,.Net 类型的多态对象将显示为名为 "$type"例如:

<块引用>

"$type": "Newtonsoft.Json.Samples.Stockholder, Newtonsoft.Json.Tests"

但是,如果您调用常规方法 JsonConvert.SerializeObject(Object)JsonSerializer.Serialize(TextWriter, Object).相反,您必须使用接受预期"根类型的序列化方法之一,例如 SerializeObject(Object, Type, JsonSerializerSettings)JsonSerializer.Serialize(TextWriter, Object, Type).传递 typeof(object) 作为预期的类型保证 type 属性会出现:

var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };var json = JsonConvert.SerializeObject(rootObject, typeof(object), settings);

如果您使用此设置创建 JSON 文件,JSON 本身将记住序列化对象的类型.Json.NET 在反序列化期间将使用此类型,只要您使用 set TypeNameHandling 设置为 TypeNameHandling.None.例如:

var settings = new Newtonsoft.Json.JsonSerializerSettings { TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto };b1 = Newtonsoft.Json.JsonConvert.DeserializeObject(fileText, settings);

工作示例 .Net fiddle 此处.

警告:这种在 JSON 中存储 .Net 类型的方式是非标准的.其他序列化程序,例如 DataContractJsonSerializer 不处理这种格式的类型信息.

还要注意 Newtonsoft 文档中的这一警告:

<块引用>

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

有关为什么需要这样做的讨论,请参阅 Newtonsoft Json 中的 TypeNameHandling 警告如何配置Json.NET 创建易受攻击的 Web API,以及 Alvaro Muñoz &Oleksandr Mirosh 的黑帽论文 https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf.

I searched through similar questions and couldn't find anything that quite matched what i was looking for.

New to C# so bear with me please.

I have some json files that i am deserializing. I want the files to deserialize to objects of the correct type, without having to define the type before hand. Here's my code:

public class loadJson
    {
        //path of the file location
        public void readJson(string path)
        {
            //array of files at the path location. right now just reading one file
            FileInfo[] files = new DirectoryInfo(path).GetFiles("seleniumExample.json").ToArray();

            foreach (FileInfo fi in files)
            {

                dynamic b1 = null;
                using (StreamReader file = new StreamReader(fi.FullName))
                {

                    string fileText = file.ReadToEnd();
                    //Console.WriteLine(fileText);

                    try
                    {
                        b1 = Newtonsoft.Json.JsonConvert.DeserializeObject(fileText);
                    }
                    catch(Exception e)
                    {
                        Console.WriteLine("ERROR!!!! " + e.ToString());
                    }

                    file.Close();
                }
            }
        }
    }

I have a bunch of object types that I will be feeding into my program through json files.

I don't want to have to explicitly call b1 a Bid, or a Client, or any other specific predefined class. If I do explicitly call b1 a Bid, it loads all the info just fine and fills out the correct instance variables.

But when I use "dynamic", or general "object", it can't figure it out and just initializes to an "object".

Is there a way to perform generic deserialization and have it create an object of the correct class based on the fields defined in the json file?

Thanks in advance for the help, and i apologize if my question is incredibly unclear. If so, please just let me know how I can help clear up any ambiguity. Thanks again.

解决方案

Json.NET has the ability to record the .Net object type of polymorphic types during serialization, by using the setting TypeNameHandling = TypeNameHandling.Auto. When the setting is enabled the .Net type of polymorphic objects will appear as a synthetic property called "$type", for instance:

"$type": "Newtonsoft.Json.Samples.Stockholder, Newtonsoft.Json.Tests"

However, the "$type" property is never emitted for the root object if you call the conventional methods JsonConvert.SerializeObject(Object) or JsonSerializer.Serialize(TextWriter, Object). Instead, you must use one of the serialization methods that accepts an "expected" root type, for instance SerializeObject(Object, Type, JsonSerializerSettings) or JsonSerializer.Serialize(TextWriter, Object, Type). Passing typeof(object) as the expected type guarantees the type property will appear:

var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
var json = JsonConvert.SerializeObject(rootObject, typeof(object), settings);

If you create your JSON files using this setting, the JSON itself will remember the type of object serialized. This type will be used by Json.NET during deserialization, as long as you use set TypeNameHandling to something other than TypeNameHandling.None. e.g.:

var settings = new Newtonsoft.Json.JsonSerializerSettings { TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto };
b1 = Newtonsoft.Json.JsonConvert.DeserializeObject(fileText, settings);

Working sample .Net fiddle here.

Caveats: this way of storing .Net types in JSON is nonstandard. Other serializers such as DataContractJsonSerializer do not process type information in this format.

Note also this caution from the Newtonsoft docs:

TypeNameHandling should be used with caution when your application deserializes JSON from an external source. Incoming types should be validated with a custom SerializationBinder when deserializing with a value other than None.

For a discussion of why this may be necessary, see TypeNameHandling caution in Newtonsoft Json, How to configure Json.NET to create a vulnerable web API, and Alvaro Muñoz & Oleksandr Mirosh's blackhat paper https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf.

这篇关于如何将 JSON 反序列化为正确类型的对象,而无需事先定义类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆