【问题标题】:Custom JsonSerializerSettings /JsonConverter for List of different Types, each type having its own serializerSettings自定义 JsonSerializerSettings /JsonConverter 用于不同类型的列表,每种类型都有自己的 serializerSettings
【发布时间】:2019-09-13 16:33:23
【问题描述】:

我有一个需要序列化为 json 字符串的 json 根 (testRoot) 的对象列表 (resultList)。该列表包含不同类型的实例(TypeA、B、C),它们有自己的 serializerSettings。

如何实现一个自定义的 JsonConverter / JsonSerializerSettings 以便当 我调用 JsonConvert.SerializeObject(testRoot),它应该根据该实例的设置序列化每个实例。

我无法找到解决问题的好方法。感谢您的帮助。

   class TypeA
    {
        public string Name { get; set; }
        public int intPropertyA { get; set; }
        public string strPropertyA { get; set; }
        public JsonSerializerSettings serializerSettingsA { get; set; }
    }

    class TypeB
    {
        public string Name { get; set; }
        public int intPropertyB { get; set; }
        public string strPropertyB { get; set; }
        public JsonSerializerSettings serializerSettingsB { get; set; }
    }

    class TypeC
    {
        public string Name { get; set; }
        public int intPropertyC { get; set; }
        public string strPropertyC { get; set; }
        public JsonSerializerSettings serializerSettingsC { get; set; }
    }

    static void Main(string[] args)
    {
        object[] resultList = new object[3];
        int i = 0;

        TypeA objA = new TypeA(); // assume all values initialized
        TypeB objB = new TypeB(); // assume all values initialized
        TypeC objC = new TypeC(); // assume all values initialized

        resultList[i++] = new
        {
            Name = objA.Name,
            IntValue = objA.intPropertyA,
            StringValue = objA.strPropertyA
        };

        resultList[i++] = new
        {
            Name = objB.Name,
            IntValue = objB.intPropertyB,
            StringValue = objB.strPropertyB
        };

        resultList[i++] = new
        {
            Name = objC.Name,
            IntValue = objC.intPropertyC,
            StringValue = objC.strPropertyC
        };                      

        object testRoot = new
        {
            Test = "All the test results",
            date = "",
            Results = resultList
        };
            // How to customize the JsonSerializerSettings/JsonConverter so that, while serializing each type it should use settings from that instace.
            string jsonStr = JsonConvert.SerializeObject(testRoot);

        }
    public class CompositeSerializerSettings : Newtonsoft.Json.JsonSerializerSettings
    {
        public CompositeSerializerSettings()
        {
        }
    }

    public class CompositeJsonConverter : Newtonsoft.Json.JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            throw new NotImplementedException();
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }

【问题讨论】:

  • 您为什么要这样做?您试图通过为每种类型使用不同的序列化程序设置来解决的潜在问题是什么?你能改用属性吗?
  • 每种类型来自不同的数据源,有自己的设置。当前的问题是当我调用字符串 jsonStr = JsonConvert.SerializeObject(testRoot) 时,它将使用默认的序列化设置来执行此操作。我希望 JsonConverter 在找到任何基于特定类型的 Name 或其他字段时以某种方式知道要使用哪些设置。
  • 您的示例使这非常困难。我开始回答,但是您的测试代码不会创建 TypeA 或 TypeB 的实例,它会创建从 TypeA 的属性派生的匿名对象等。所以我真的不知道您希望转换器如何找到设置。跨度>
  • 谢谢@stuartd。它有帮助。

标签: c# json.net


【解决方案1】:

正如我在上面的评论中指出的那样,这并不能完全回答您的问题,因为在您的测试代码中,您没有传递 TypeA 或 TypeB 或 TypeC 的实例,而是传递了从这些类派生的匿名对象。

但是,如果您实际上是在尝试序列化对象本身而不是匿名对象,并且希望序列化程序为每种类型使用自定义设置,则必须告诉它如何找到它们。

使用界面是一种选择:请注意,您必须“忽略”设置,否则它们会出现在序列化输出中 - 我设置缩进纯粹是为了表明这是有效的。

public interface ISerializerSettings
{
    JsonSerializerSettings serializerSettings { get;}
}

class TypeA : ISerializerSettings
{
    public string Name { get; set; }
    public int intPropertyA { get; set; }
    public string strPropertyA { get; set; }
    [JsonIgnore]
    public JsonSerializerSettings serializerSettings { get; } = new JsonSerializerSettings
    {
        Formatting = Formatting.Indented
    };
}

class TypeB : ISerializerSettings
{
    public string Name { get; set; }
    public int intPropertyB { get; set; }
    public string strPropertyB { get; set; }
    [JsonIgnore]
    public JsonSerializerSettings serializerSettings { get; } = new JsonSerializerSettings
    {
        Formatting = Formatting.None
    };
}

class TypeC : ISerializerSettings
{
    public string Name { get; set; }
    public int intPropertyC { get; set; }
    public string strPropertyC { get; set; }
    [JsonIgnore]
    public JsonSerializerSettings serializerSettings { get; } = new JsonSerializerSettings
    {
        Formatting = Formatting.Indented
    };
}

然后在转换器中,使用类型的设置:

public class CompositeJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(ISerializerSettings).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteRaw(JsonConvert.SerializeObject(value, ((ISerializerSettings)value).serializerSettings));
    }
}

最后,在你的程序中,告诉序列化器使用你的转换器:

string jsonStr = JsonConvert.SerializeObject(testRoot, new CompositeJsonConverter());

给定这个输入:

TypeA objA = new TypeA(); // assume all values initialized
TypeB objB = new TypeB(); // assume all values initialized
TypeC objC = new TypeC(); // assume all values initialized

object[] resultList = new object[] {
            objA, objB, objC
};

object testRoot = new
{
    Test = "All the test results",
    date = "",
    Results = resultList
};

string jsonStr = JsonConvert.SerializeObject(testRoot, new CompositeJsonConverter());

这是输出:注意 TypeB 没有格式,但其他有:

{"Test":"All the test results","date":"","Results":[{
  "Name": null,
  "intPropertyA": 0,
  "strPropertyA": null
}{"Name":null,"intPropertyB":0,"strPropertyB":null}{
  "Name": null,
  "intPropertyC": 0,
  "strPropertyC": null
}]}

【讨论】:

  • 如何使结果记录用逗号分隔? “结果”:[{“名称”:空,“intPropertyA”:0,“strPropertyA”:空},{“名称”:空,“intPropertyB”:0,“strPropertyB”:null},{“名称”:空,“intPropertyC”:0,“strPropertyC”:空}]
  • 嗯,好点。结果不是有效的 JSON,抱歉 - 我之前没有注意到。
猜你喜欢
  • 1970-01-01
  • 2016-08-26
  • 2015-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-27
  • 1970-01-01
相关资源
最近更新 更多