C#元素创建一个特定的json输出

时间:2017-09-23 11:11:07

标签: c# asp.net json json.net

从C#aspnet核心控制器

我产生以下输出:

[
{
    "info": {
        "type": 6,
        "message": "a message"
    }
},
{
    "detail": {
        "type": 8,
        "something": "a different thing"
     }
}
]

我现在正在这样做:

Dictionary<string, object> Result = new Dictionary<string, object>();
Result.Add("info", new Info() { Type = 6, message = "a message"});
Result.Add("detail", new Detail() { Type = 8, something = "a different thing" });
JsonConvert.SerializeObject(new object[] { _Errors });

但是当涉及到这样的输出时,这不起作用:

[
{
    "info": {
        "type": 6,
        "message": "a message"
    }
},
{
    "info": {
        "type": 6,
        "message": "another message"
     }
}
]

由于这需要字典中的重复键,我不知道哪个结构将产生这个输出。

KeyValuePair不会工作,因为这导致“key”:“info”......等等。 此外,由于元素数量是动态的,因此具有多个使用相同JsonProperty属性的成员的类将无法工作。

2 个答案:

答案 0 :(得分:1)

我假设你想要的是这个输出:

[
  {
    "Info": {
      "Type": 5,
      "Message": "A message 1"
    }
  },
  {
    "Info": {
      "Type": 6,
      "Message": "A message 3"
    }
  },
  {
    "Info": {
      "Type": 7,
      "Message": "A message 2"
    }
  },
  {
    "Error": {
      "Type": 8,
      "Something": "A different thing"
    }
  }
]

实现自己的JsonConvert,这是一个提供上述序列化

的示例
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;

namespace JsonSerialization
{
    public class ResultsEntrySerializer : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var entry = value as IResultsEntry;
            if (entry == null) throw new ArgumentException("Cannot convert parameter", nameof(value));
            writer.WriteStartObject();
            writer.WritePropertyName(entry.Name);
            serializer.Serialize(writer, entry.Entry);
            writer.WriteEndObject();
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            //TODO: I leave this up to the reader
            throw new NotImplementedException();
        }

        public override bool CanConvert(Type objectType)
        {
            return objectType.GetInterfaces().Contains(typeof(IResultsEntry));
        }
    }

    [JsonConverter(typeof(ResultsEntrySerializer))]
    interface IResultsEntry
    {
        string Name { get; }
        object Entry { get; set; }
    }

    class Info
    {
        public int Type { get; set; }
        public string Message { get; set; }
    }

    class InfoEntry : IResultsEntry
    {
        string IResultsEntry.Name => "Info";

        object IResultsEntry.Entry
        {
            get => Entry;
            set => Entry = (Info)value;
        }

        public Info Entry { get; set; }
    }

    class Detail
    {
        public int Type { get; set; }
        public string Something { get; set; }
    }

    class DetailEntry : IResultsEntry
    {
        string IResultsEntry.Name => "Error";

        object IResultsEntry.Entry
        {
            get => Entry;
            set => Entry = (Detail)value;
        }

        public Detail Entry { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var list = new List<IResultsEntry>
            {
                new InfoEntry
                {
                    Entry = new Info { Type = 5, Message = "A message 1" }
                },
                new InfoEntry
                {
                    Entry = new Info { Type = 6, Message = "A message 3" }
                },
                new InfoEntry
                {
                    Entry = new Info { Type = 7, Message = "A message 2" }
                },
                new DetailEntry
                {
                    Entry = new Detail { Type = 8, Something = "A different thing" }
                }
            };
            Console.WriteLine(JsonConvert.SerializeObject(list));
            Console.ReadLine();
        }
    }
}

此外,如果你想要它们的小写也是微不足道的,请看这个Stackoverflow帖子:Json keys lowercase

答案 1 :(得分:0)

抱歉这令人困惑。在检查了一些事情之后我发现(不是真的)一个解决方案。 我想出了一本有特殊键的字典。 Json.Net只使用ToString()作为字典键,所以像这样的东西似乎做了我想要的。

    public class DupKey {
    public string Name { get; set; }
    public int Index { get; set; }
    public override string ToString() {
        return Name;
    }
    public override bool Equals(object obj) {
        if(!(obj is DupKey)) return false;
        return Index == ((DupKey)obj).Index;
    }
    public override int GetHashCode() {
        return Index.GetHashCode();
    }
}

但最后我发现这会产生错误的结果。 最后,我发现了一个解决方案(不需要自己的序列化器),它可以提供正确的结果。

因为这对我来说看起来很普遍,所以我在这里发布。

    public class DynamicJsonEntry : DynamicObject {
    private string _JsonName;
    public object Element { get; set; }
    public DynamicJsonEntry(string pJsonName, object pElement) : this(pJsonName) {
        Element = pElement;
    }
    public DynamicJsonEntry(string pJsonName) {
        if(string.IsNullOrWhiteSpace(pJsonName)) {
            throw new ArgumentNullException(nameof(pJsonName));
        }
        _JsonName = pJsonName;
    }
    public override IEnumerable<string> GetDynamicMemberNames() {
        yield return _JsonName;
        foreach(var prop in GetType().GetProperties().Where(a => a.CanRead && a.GetIndexParameters().Length == 0 && a.Name != nameof(Element))) {
            yield return prop.Name;
        }
    }
    public override bool TryGetMember(GetMemberBinder pBinder, out object pResult) {
        if(pBinder.Name == _JsonName) {
            pResult = Element;
            return true;
        }
        return base.TryGetMember(pBinder, out pResult);
    }
}

现在我可以像这样添加任何名称我想要的条目:

List<DynamicJsonEntry> lRet = new List<DynamicJsonEntry>();
lRet.Add(new DynamicJsonEntry("info", new Info() { Type = 6, message = "a message" }));
lRet.Add(new DynamicJsonEntry("detail", new Detail() { Type = 8, something = "a different thing" }));
lRet.Add(new DynamicJsonEntry("info", new Info() { Type = 6, message = "a second message" }));

感谢Joachim的帮助。