如何将具有索引器属性的集合序列化为字典

7
我有一个类,比如叫做 FooCollection,它实现了 IEnumerable<Foo> 接口,并且提供了一个索引器,可以通过名称查找 Foo。从功能上来看,它就像一个只读的字典。但它并不是真正的字典,因为用户不能决定键。
无论如何,我希望 JSON.NET 将这个对象序列化为 JSON 字典,而不是数组,因为现在它正在以数组的形式进行序列化。将 JsonDictionaryAttribute 标记应用于该对象并没有起作用:仍然会以数组形式进行序列化。
有什么提示吗?

1
为什么不直接发布你的代码,而是描述整个过程呢? - I4V
1个回答

13

为了按照您的需求对FooCollection类进行序列化,您可能需要创建一个定制的JsonConverter。由于您还没有发布任何代码,我将仅以示例为例来说明。假设您的FooFooCollection类如下所示:

class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class FooCollection : IEnumerable<Foo>
{
    private List<Foo> list = new List<Foo>();

    public void Add(Foo foo)
    {
        list.Add(foo);
    }

    public Foo this[string name]
    {
        get { return list.Find(f => f.Name == name); }
    }

    public IEnumerator<Foo> GetEnumerator()
    {
        return list.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable)list).GetEnumerator();
    }
}
以下转换器将序列化 FooCollection,就好像它是一个字典。我假设你想要转换器使用每个 FooName 属性值作为序列化的键(以匹配集合上的索引器),所以我是这样实现的。你可以通过修改 GetFooKey() 方法来改变它到其他的东西。
class FooCollectionConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(FooCollection));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteStartObject();
        foreach (Foo foo in (FooCollection)value)
        {
            writer.WritePropertyName(GetFooKey(foo));
            serializer.Serialize(writer, foo);
        }
        writer.WriteEndObject();
    }

    // Given a Foo, return its unique key to be used during serialization
    private string GetFooKey(Foo foo)
    {
        return foo.Name;
    }

    public override bool CanRead
    {
        get { return false; }
    }

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

这是一个示例程序,演示如何使用转换器。

class Program
{
    static void Main(string[] args)
    {
        FooCollection coll = new FooCollection();
        coll.Add(new Foo { Id = 1, Name = "Moe" });
        coll.Add(new Foo { Id = 2, Name = "Larry" });
        coll.Add(new Foo { Id = 3, Name = "Curly" });

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.Converters.Add(new FooCollectionConverter());
        settings.Formatting = Newtonsoft.Json.Formatting.Indented;

        string json = JsonConvert.SerializeObject(coll, settings);

        Console.WriteLine(json);
    }
}

以下是上述程序的输出结果:

{
  "Moe": {
    "Id": 1,
    "Name": "Moe"
  },
  "Larry": {
    "Id": 2,
    "Name": "Larry"
  },
  "Curly": {
    "Id": 3,
    "Name": "Curly"
  }
}

演示代码: https://dotnetfiddle.net/wI2iQG


你能分享一下ReadJson方法的示例吗? - Oscar Canek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接