如何将JSON反序列化为正确类型的对象,而不必事先定义类型?

时间:2015-04-17 01:04:10

标签: c# json serialization deserialization

我搜索了类似的问题,找不到与我想要的完全匹配的任何东西。

C#的新手请跟我说。

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

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();
                }
            }
        }
    }

我有一堆对象类型,我将通过json文件提供给我的程序。

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

但是当我使用“动态”或一般的“对象”时,它无法解决它并只是初始化为“对象”。

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

提前感谢您的帮助,如果我的问题非常不清楚,我会道歉。如果是这样,请让我知道如何帮助消除任何歧义。再次感谢。

2 个答案:

答案 0 :(得分:14)

Json.NET能够使用设置TypeNameHandling = TypeNameHandling.Auto在序列化期间记录.Net对象类型的多态类型。启用该设置后,.Net类型的多态对象将显示为名为"$type"的合成属性for instance

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

但是,如果您调用常规方法JsonConvert.SerializeObject(Object)JsonSerializer.Serialize(TextWriter, Object),则 root 对象永远不会发出"$type"属性。相反,您必须使用一种接受“预期”根类型的序列化方法,例如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本身将记住序列化对象的类型。只要您将TypeNameHandling设置为TypeNameHandling.None之外的其他内容,Json.NET将在反序列化期间使用此类型。 e.g:

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

工作样本.Net小提琴here

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

请注意Newtonsoft docs

中的这一注意事项
  

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

有关为何需要这样做的讨论,请参阅TypeNameHandling caution in Newtonsoft JsonHow to configure Json.NET to create a vulnerable web API和AlvaroMuñoz& Oleksandr Mirosh的黑帽纸https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf

答案 1 :(得分:0)

将您的JSON反序列化为最基本的形式:

Dictionary<string, object> theData= new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(jsonString);

string baseItemName = (string)theData["baseItem"];

Dictionary<string, object> someNode= (Dictionary<string, object>)theData["something"];

string anything = (string)someNode["anything"];
string nothing = (string)someNode["nothing"];

Deserialize()的调用会创建一个Dictionary<string, object>树,您可以随意浏览。