.Net Core 3.0 JsonSerializer填充现有对象 [英] .Net Core 3.0 JsonSerializer populate existing object

查看:427
本文介绍了.Net Core 3.0 JsonSerializer填充现有对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在准备从ASP.NET Core 2.2迁移到3.0.

I'm preparing a migration from ASP.NET Core 2.2 to 3.0.

由于我不再使用任何更高级的JSON功能(但可能如下所述),并且3.0现在带有JSON的内置名称空间/类,System.Text.Json,所以我决定看看是否可以删除以前的默认Newtonsoft.Json.请注意,我知道System.Text.Json不会完全取代Newtonsoft.Json.

As I don't use any more advanced JSON features (but maybe one as described below), and 3.0 now comes with a built-in namespace/classes for JSON, System.Text.Json, I decided to see if I could drop the previous default Newtonsoft.Json. Do note, I'm aware that System.Text.Json will not completely replace Newtonsoft.Json.

我设法在任何地方都做到了,例如

I managed to do that everywhere, e.g.

var obj = JsonSerializer.Parse<T>(jsonstring);

var jsonstring = JsonSerializer.ToString(obj);

但是在一个地方,我要填充现有对象.

but in one place, where I populate an existing object.

使用Newtonsoft.Json可以做到

JsonConvert.PopulateObject(jsonstring, obj);


内置的System.Text.Json命名空间还有一些其他类,例如JsonDocumnetJsonElementUtf8JsonReader,尽管我找不到任何将现有对象作为参数的类.


The built-in System.Text.Json namespace has some additional classes, like JsonDocumnet, JsonElement and Utf8JsonReader, though I can't find any that take an existing object as a parameter.

我也没有足够的经验来了解如何利用现有的.

Nor am I experienced enough to see how to make use of the existing one's.

.Net Core中可能即将发布的功能(感谢 Mustafa Gursel 作为链接),但与此同时(如果没有的话)...

There might be a possible upcoming feature in .Net Core (thanks to Mustafa Gursel for the link), but meanwhile (and what if it doesn't),...

...我现在想知道,是否有可能实现与PopulateObject相似的功能?

...I now wonder, is it possible to achieve something similar as what one can do with PopulateObject?

我的意思是,是否可以使用其他任何System.Text.Json类来实现相同的功能,并且仅更新/替换设置的属性?,...或其他一些聪明的解决方法?

I mean, is it possible with any of the other System.Text.Json classes to accomplish the same, and update/replace only the properties set?,... or some other clever workaround?

以下是其外观的示例(并且必须是通用的,因为传递给反序列化方法的对象的类型为<T>).我有2个Json字符串要解析为一个对象,其中第一个设置了一些默认属性,第二个设置了例如

Here is a sample of how it could look like (and it need to be generic as the object passed into the deserialization method is of type <T>). I have 2 Json string's to be parsed into an object, where the first have some default properties set, and the second some, e.g.

注意,属性值可以是string 以外的任何其他类型.

Note, a property value can be of any other type than a string.

Json字符串1:

{
  "Title": "Startpage",
  "Link": "/index",
}

Json字符串2:

{
  "Head": "Latest news"
  "Link": "/news"
}

使用上面的2个Json字符串,我想要一个导致以下结果的对象:

Using the 2 Json strings above, I want an object resulting in:

{
  "Title": "Startpage",
  "Head": "Latest news",
  "Link": "/news"
}

如上例所示,如果在第二个属性中设置了value/,它将替换第一个属性中的值(如"Head"和"Link"),否则,现有值将保持不变(如"Title" )

As seen in above sample, if properties in the 2nd has values/is set, it replace values in the 1st (as with "Head" and "Link"), if not, existing value persist (as with "Title")

推荐答案

解决方法也可以如此简单(也支持多级JSON):

The workaround can also be as simple as this (supports multi-level JSON as well):

using System;
using System.Linq;
using System.Reflection;
using System.Text.Json.Serialization;

namespace ConsoleApp
{
    public class Model
    {
        public Model()
        {
            SubModel = new SubModel();
        }

        public string Title { get; set; }
        public string Head { get; set; }
        public string Link { get; set; }
        public SubModel SubModel { get; set; }
    }

    public class SubModel
    {
        public string Name { get; set; }
        public string Description { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var model = new Model();

            Console.WriteLine(JsonSerializer.ToString(model));

            var json1 = "{ \"Title\": \"Startpage\", \"Link\": \"/index\" }";

            model = Map<Model>(model, json1);

            Console.WriteLine(JsonSerializer.ToString(model));

            var json2 = "{ \"Head\": \"Latest news\", \"Link\": \"/news\", \"SubModel\": { \"Name\": \"Reyan Chougle\" } }";

            model = Map<Model>(model, json2);

            Console.WriteLine(JsonSerializer.ToString(model));

            var json3 = "{ \"Head\": \"Latest news\", \"Link\": \"/news\", \"SubModel\": { \"Description\": \"I am a Software Engineer\" } }";

            model = Map<Model>(model, json3);

            Console.WriteLine(JsonSerializer.ToString(model));

            var json4 = "{ \"Head\": \"Latest news\", \"Link\": \"/news\", \"SubModel\": { \"Description\": \"I am a Software Programmer\" } }";

            model = Map<Model>(model, json4);

            Console.WriteLine(JsonSerializer.ToString(model));

            Console.ReadKey();
        }

        public static T Map<T>(T obj, string jsonString) where T : class
        {
            var newObj = JsonSerializer.Parse<T>(jsonString);

            foreach (var property in newObj.GetType().GetProperties())
            {
                if (obj.GetType().GetProperties().Any(x => x.Name == property.Name && property.GetValue(newObj) != null))
                {
                    if (property.GetType().IsClass && property.PropertyType.Assembly.FullName == typeof(T).Assembly.FullName)
                    {
                        MethodInfo mapMethod = typeof(Program).GetMethod("Map");
                        MethodInfo genericMethod = mapMethod.MakeGenericMethod(property.GetValue(newObj).GetType());
                        var obj2 = genericMethod.Invoke(null, new object[] { property.GetValue(newObj), JsonSerializer.ToString(property.GetValue(newObj)) });

                        foreach (var property2 in obj2.GetType().GetProperties())
                        {
                            if (property2.GetValue(obj2) != null)
                            {
                                property.GetValue(obj).GetType().GetProperty(property2.Name).SetValue(property.GetValue(obj), property2.GetValue(obj2));
                            }
                        }
                    }
                    else
                    {
                        property.SetValue(obj, property.GetValue(newObj));
                    }
                }
            }

            return obj;
        }
    }
}

输出:

这篇关于.Net Core 3.0 JsonSerializer填充现有对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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