【问题标题】:JObject.FromObject null refrence exception while working with derived classes使用派生类时 JObject.FromObject 空引用异常
【发布时间】:2021-10-01 12:09:16
【问题描述】:

我想反序列化具有字典 属性的类。模块是多个子类的基类。反序列化后,我显然希望属性包含子类的实例。

目前我正在尝试实现自定义 JsonConverter。问题是我的代码在 CustomJsonConverter.WriteJson() 函数中失败。 JObject.FromObject() 引发空异常。 我做错了什么?

一个完整的控制台项目:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json.Linq;

namespace HowToSerializeJson
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            var map = new Map();
            var modules = new Dictionary<string, Module>
            {
                {"test1", new Module1("id1")},
                {"test2", new Module2("id2")},
            };
            map.Modules = modules;
            map.SaveJson();
            map.LoadJson();
    }
}

class Map
{
    public Dictionary<string,Module> Modules { get; set; }

    public bool LoadJson()
    {
        try
        {
            if (File.Exists("mapping.json"))
            {

                using (StreamReader file = File.OpenText("$mapping.json"))
                {
                    var text = file.ReadToEnd();
                    var json = JsonConvert.DeserializeObject(text, new JsonSerializerSettings
                    {
                        TypeNameHandling = TypeNameHandling.All,
                        TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full,
                        ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                        NullValueHandling = NullValueHandling.Ignore
                    });
                    var map = json as Map;
                    Modules = map.Modules;
                }


                return true;
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);

        }
        return false;
    }

    public bool SaveJson()
    {
        using (StreamWriter file = File.CreateText("mapping.json"))
        {

            var json = JsonConvert.SerializeObject(this, Formatting.Indented, new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.All,
                TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                NullValueHandling = NullValueHandling.Ignore
            });
            file.Write(json);
        }
        return false;
    }
}

[JsonConverter(typeof(CustomJsonConverter))]
class Module
{
    public string Id { get; set; }

    public Module(string id)
    {
        Id = id;
    }
}

[JsonConverter(typeof(CustomJsonConverter))]
class Module1 : Module
{
    public string Prop1 { get; set; } = "1";
    public Module1(string id) : base(id)
    {
    }
}

[JsonConverter(typeof(CustomJsonConverter))]
class Module2 : Module
{
    public string Prop1 { get; set; } = "2";
    public Module2(string id) : base(id)
    {
    }
}

public class CustomJsonConverter : JsonConverter
{

    public List<Type> Types { get; set; } = Assembly.GetAssembly(typeof(CustomJsonConverter)).GetTypes().ToList();

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        try
        {
            var jObj = JObject.FromObject(value, serializer);
            jObj.AddFirst(new JProperty("type", value.GetType().Name));
            jObj.WriteTo(writer);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return null;
        }
        var obj = JObject.Load(reader);
        var typeKey = obj["$type"];
        if (typeKey == null)
        {
            throw new InvalidOperationException("Cannot deserialize object w/o 'type' property.");
        }
        obj.Remove("type");

        var type = Types.First(x => x.Name == typeKey.Value<string>());

        var contract = serializer.ContractResolver.ResolveContract(type);
        var value = contract.DefaultCreator();

        if (value == null)
        {
            throw new JsonSerializationException("No object created.");
        }

        using (var subReader = obj.CreateReader())
        {
            serializer.Populate(subReader, value);
        }

        return value;

    }

    public override bool CanConvert(Type objectType)
    {
        return Types.Contains(objectType);
    }
}

}

如果 ReadJson()(或整个方法)有问题,我会为每一个输入感到高兴。

【问题讨论】:

    标签: c# json json.net


    【解决方案1】:

    事实上,您可以摆脱自定义转换器。多态性已经由您的JsonSerializerSettings 处理,即使结果很冗长。

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            var map = new Map();
            var modules = new Dictionary<string, Module>
            {
                {"test1", new Module1("id1")},
                {"test2", new Module2("id2")},
            };
            map.Modules = modules;
            map.SaveJson();
            map.LoadJson();
        }
    }
    
    class Map
    {
        public Dictionary<string, Module> Modules { get; set; }
    
        public bool LoadJson()
        {
            try
            {
                if (File.Exists("mapping.json"))
                {
    
                    using (StreamReader file = File.OpenText("mapping.json"))
                    {
                        var text = file.ReadToEnd();
                        var json = JsonConvert.DeserializeObject(text, new JsonSerializerSettings
                        {
                            TypeNameHandling = TypeNameHandling.All,
                            TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full,
                            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                            NullValueHandling = NullValueHandling.Ignore
                        });
                        var map = json as Map;
                        Modules = map.Modules;
                    }
    
    
                    return true;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
    
            }
            return false;
        }
    
        public bool SaveJson()
        {
            using (StreamWriter file = File.CreateText("mapping.json"))
            {
    
                var json = JsonConvert.SerializeObject(this, Formatting.Indented, new JsonSerializerSettings
                {
                    TypeNameHandling = TypeNameHandling.All,
                    TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full,
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                    NullValueHandling = NullValueHandling.Ignore
                });
                file.Write(json);
            }
            return false;
        }
    }
    
    class Module
    {
    
        public string Id { get; set; }
    
        public Module(string id)
        {
            Id = id;
        }
    }
    
    class Module1 : Module
    {
        public string Prop1 { get; set; } = "1";
        public Module1(string id) : base(id)
        {
        }
    }
    
    class Module2 : Module
    {
        public string Prop1 { get; set; } = "2";
        public Module2(string id) : base(id)
        {
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-30
      • 1970-01-01
      • 1970-01-01
      • 2012-01-28
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多