【问题标题】:Deserialize JSON into Derived classes将 JSON 反序列化为派生类
【发布时间】:2017-06-05 18:38:24
【问题描述】:
{
    "Class1": {
        "Class2": [
            {"Name": "DerivedV1"},
            {"Name": "DerivedV2"},
            {"Name": "DerivedV3"}
        ]
    }
}

JsonConvert.DeserializeObject<Class1>(jsonString, settings);

public class Class1
{
    public List<BaseClass> DerivedClasses { get; set; }
}

public abstract BaseClass
{
    public string Name { get; set; }

    public abstract bool DoSomething;
}

public class DerivedV1 : BaseClass
{
    public override bool DoSomething()
    {
        // Logic here, different for each derived class.
    }
}

在尝试反序列化 Class1 时,我不知道如何创建从名称分类的派生类列表。我不能声明类似于 List BaseClass 的东西,其中 BaseClass 是抽象的,我不确定如何在 Class2 内的反序列化期间使用反射来从“名称”值确定派生类。我还研究了 ICloneable,但在这种情况下没有得到任何结果。

编辑:

这是我最终从 get 和 set 创建和调用的内容

    public static List<T> DeserializeJObjectsToObjects<T>(IEnumerable<JObject> jObjects, string typeKey, string nameSpaceOfClass)
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        List<T> convert = new List<T>();

        foreach (var jObject in jObjects)
        {
            JToken typeName;
            jObject.TryGetValue(typeKey, out typeName);
            string fullNameSpace = string.Format(namespaceFormat, nameSpaceOfClass, typeName);
            Type t = Type.GetType(string.Format(fullNameSpace));
            convert.Add((T) Activator.CreateInstance(t));
        }

        return convert;
    }

    public static List<JObject> SerializeObjectsToJObjects<T>(IEnumerable<T> variableObjects )
    {
        List<JObject> convert = new List<JObject>();

        foreach (T variableObject in variableObjects)
        {
            var jsonString = JsonConvert.SerializeObject(variableObject);
            convert.Add(JObject.Parse(jsonString));
        }

        return convert;
    }

【问题讨论】:

  • 能否提供一些您在反序列化过程中尝试过的代码?
  • 您要达到什么目的,反序列化您提供的 json 的预期结果是什么?
  • 添加了一些我尝试过的基本代码,这些代码不起作用,但希望能显示我正在尝试做的事情。

标签: c# .net json serialization deserialization


【解决方案1】:

将此作为我的解决方案。

  public static List<T> DeserializeJObjectsToObjects<T>(IEnumerable<JObject> jObjects, string typeKey, string nameSpaceOfClass)
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        List<T> convert = new List<T>();

        foreach (var jObject in jObjects)
        {
            JToken typeName;
            jObject.TryGetValue(typeKey, out typeName);
            string fullNameSpace = string.Format(nameSpaceFormat, nameSpaceOfClass, typeName);
            Type t = Type.GetType(string.Format(fullNameSpace));
            convert.Add((T) Activator.CreateInstance(t));
        }

        return convert;
    }

    public static List<JObject> SerializeObjectsToJObjects<T>(IEnumerable<T> variableObjects )
    {
        List<JObject> convert = new List<JObject>();

        foreach (T variableObject in variableObjects)
        {
            var jsonString = JsonConvert.SerializeObject(variableObject);
            convert.Add(JObject.Parse(jsonString));
        }

        return convert;
    }

【讨论】:

    【解决方案2】:

    首先,一些注意事项 - 我不使用 JSonConvert,但有一些文章向您展示了如何使用它。例如,请参阅Json.net serialize/deserialize derived types?。但是,您没有包含 json.net 标记,所以我假设这应该会有所帮助,或者至少将您指向正确的位置。

    我使用了内置的 .Net JavaScriptSerializer。您可能需要调整它以使用您的输入。我根据你的代码创建了我的输入,我的 json 看起来不像你的。所以,你可能还有一些工作要做。 我能够让它与 SimpleTypeResolver 一起工作。代码如下:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Web.Script.Serialization;
    using System.Windows.Forms;
    using System.Xml.Serialization;
    
    namespace WindowsFormsApplication6
    {
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
            Class1 oClass = new Class1();
            DerivedV1 v1 = new DerivedV1();
            v1.Name = "DerivedV1";
            oClass.DerivedClasses.Add(v1);
            DerivedV2 v2 = new DerivedV2();
            v2.Name = "DerivedV2";
            oClass.DerivedClasses.Add(v2);
            DerivedV3 v3 = new DerivedV3();
            v3.Name = "DerivedV3";
            oClass.DerivedClasses.Add(v3);
            JavaScriptSerializer ser = new JavaScriptSerializer(new SimpleTypeResolver());
            string sSer = ser.Serialize(oClass);
    
            var test =ser.Deserialize(sSer,typeof(Class1));
            foreach (var tst in ((Class1)test).DerivedClasses)
            {
                Console.WriteLine(tst.Name + Environment.NewLine);
                Console.WriteLine(tst.GetType().ToString() + Environment.NewLine);
            }
        }
        public class Class1
        {
            public List<BaseClass> DerivedClasses { get; set; }
            public Class1()
            {
                DerivedClasses = new List<BaseClass>();
            }
        }
        public abstract class BaseClass
        {
            public string Name { get; set; }
            private bool _dosom;
    
            public abstract bool DoSomething();
            public BaseClass(){}
        }       
        public class DerivedV1 : BaseClass
        {
            public override bool DoSomething()
            {
                return true;
                // Logic here, different for each derived class.
            }
        }
        public class DerivedV2 : BaseClass
        {
            public override bool DoSomething()
            {
                return false;
                // Logic here, different for each derived class.
            }
        }
        public class DerivedV3 : BaseClass
        {
            public override bool DoSomething()
            {
                return true;
                // Logic here, different for each derived class.
            }
        }
    }
    }
    

    我的输出 json(使用 SimpleTypeResolver):

    {"__type":"WindowsFormsApplication6.Form1+Class1, WindowsFormsApplication6, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","DerivedClasses":[{"__type":"WindowsFormsApplication6.Form1+DerivedV1, WindowsFormsApplication6, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Name":"DerivedV1"},{"__type":"WindowsFormsApplication6.Form1+DerivedV2, WindowsFormsApplication6, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Name":"DerivedV2"},{"__type":"WindowsFormsApplication6.Form1+DerivedV3, WindowsFormsApplication6, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Name":"DerivedV3"}]}
    

    并且没有类型解析器,用于比较(导致错误):

    {"DerivedClasses":[{"Name":"DerivedV1"},{"Name":"DerivedV2"},{"Name":"DerivedV3"}]}
    

    一旦我反序列化(在 for 循环中,Console.WriteLine)...

    DerivedV1
    
    WindowsFormsApplication6.Form1+DerivedV1
    
    DerivedV2
    
    WindowsFormsApplication6.Form1+DerivedV2
    
    DerivedV3
    
    WindowsFormsApplication6.Form1+DerivedV3 
    

    【讨论】:

    • 如果您直接从用户输入的文本中反序列化,这将不起作用。当您在对象上使用 JavaScriptSerializer 时,您会添加其他信息,例如“__type”:“WindowsFormsApplication6.Form1+DerivedV2。在某些情况下您是对的,但不完全是我想要的。我想让 JSON 模板创建变得简单尽可能在我的用户上。
    • 是的,它需要以这种方式序列化。如果没有不同,他将需要访问 json 创建软件。我相信如果他不能生成 json,他将需要使用 1 类类型,并使用基于名称(或其他属性)的逻辑来“DoSomething”。但是要在不告诉它什么派生类型的情况下将派生类型放入基类型列表中?我很确定您必须自己编写代码。你能想出一种方法来使用现有的序列化器吗?
    • 没有,我不认为。我还没有看到一种方法来指定一个值来推断类类型。我现在拥有这种“工作”的方式是,在 DervcedClasses 属性的 BaseClass 中,我有 getter 和 setter 只是操纵从 JSON 创建的 JObjects 的私有列表。 getter 使用 Activator 创建正确的实例,setter 只是序列化每个元素并设置列表。
    • 我认为你可以写它..我会玩一点。不过,这可能会很习惯。但我很确定我可以在其中传入类型的“类型”属性。 name 属性是否总是与类型名称匹配?
    • 我做了一个辅助方法,但我认为这将是一个简单的选择。我在 JSON 的另一个分支中使用“类型”作为键。这里的name代表要调用的模块,type中的other代表VirtualMachine等资源。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-22
    • 2012-05-25
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多