在实现IEnumerable的类上序列化自定义属性 [英] Serialize custom properties on a class that implements IEnumerable

查看:72
本文介绍了在实现IEnumerable的类上序列化自定义属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当前,JSON.NET会忽略实现IEnumerable的类的所有其他属性,并序列化数组.

Currently, JSON.NET ignores all other properties on classes implementing IEnumerable and serializes the array.

如何告诉JSON.NET序列化自定义属性?我正在尝试序列化下面的PagedList<T>实现:

How can I tell JSON.NET to serialize the custom properties? I'm trying to serialize the PagedList<T> implementation below:

public interface IPagedList : IEnumerable
{
    int PageIndex { get; }
    int PageSize { get; }
    int TotalCount { get; }
    int TotalPages { get; }
    bool HasPreviousPage { get; }
    bool HasNextPage { get; }
}

public interface IPagedList<T> : IPagedList, IList<T>
{
}

/// <summary>
/// A tried and tested PagedList implementation
/// </summary>
public class PagedList<T> : List<T>, IPagedList<T>
{
    public PagedList(IEnumerable<T> source, int pageIndex, int pageSize) :
        this(source.GetPage(pageIndex, pageSize), pageIndex, pageSize, source.Count()) { }

    public PagedList(IEnumerable<T> source, int pageIndex, int pageSize, int totalCount)
    {
        Ensure.Argument.NotNull(source, "source");

        this.TotalCount = totalCount;
        this.TotalPages = totalCount / pageSize;

        if (totalCount % pageSize > 0)
            TotalPages++;

        this.PageSize = pageSize;
        this.PageIndex = pageIndex;

        this.AddRange(source.ToList());
    }

    public int PageIndex { get; private set; }
    public int PageSize { get; private set; }
    public int TotalCount { get; private set; }
    public int TotalPages { get; private set; }

    public bool HasPreviousPage { get { return (PageIndex > 0); } }
    public bool HasNextPage { get { return (PageIndex + 1 < TotalPages); } }
}

推荐答案

我遇到了同样的问题,最终不得不使用自定义转换器来实现.我的转换器使用要操作而不是全局工作的类型名称列表.我参加了您的课程,并编写了一个小型控制台应用程序,它将通过转换器运行您的课程.魔术是在JsonSerializerSettings的设置中使用EnumerableConverter类.设置完成后,您必须在SerializeObject调用中使用设置对象.

I had the same problem and ended up having to use a custom converter to do it. My converter takes a list of type names to operate on rather than working globally. I took your class and wrote a small console application that will run your class through the converter. The magic is in the setup of the JsonSerializerSettings to use the EnumerableConverter class. Once that's setup you must use the settings object in the SerializeObject calls.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Newtonsoft.Json;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            var pagedList = new PagedList<MyObject>(
                                new MyObject[] { 
                                    new MyObject { Foo = "Bar" }, 
                                    new MyObject { Foo = "Baz" } 
                                }, 0, 2, 2);
            Debug.WriteLine(JsonConvert.SerializeObject(pagedList));
            // Outputs: [{"Foo":"Bar"},{"Foo":"Baz"}]

            var settings = new JsonSerializerSettings
            {
                Converters = new List<JsonConverter>(
                                new[]{
                                    new EnumerableConverter(
                                       new []{"ConsoleApplication2.PagedList"}, 
                                              false)
                                })
            };
            Debug.WriteLine(JsonConvert.SerializeObject(pagedList, settings));
            // Outputs: 
            //{
            //   "PageIndex":0,
            //   "PageSize":2,
            //   "TotalCount":2,
            //   "TotalPages":1,
            //   "HasPreviousPage":false,
            //   "HasNextPage":false,
            //   "Capacity":4,
            //   "Count":2,
            //   "Items":[
            //      {
            //         "Foo":"Bar"
            //      },
            //      {
            //         "Foo":"Baz"
            //      }
            //   ]
            //}      
        }
    }

    public class MyObject
    {
        public string Foo { get; set; }
    }

    public interface IPagedList : IEnumerable
    {
        int PageIndex { get; }
        int PageSize { get; }
        int TotalCount { get; }
        int TotalPages { get; }
        bool HasPreviousPage { get; }
        bool HasNextPage { get; }
    }

    public interface IPagedList<T> : IPagedList, IList<T>
    {
    }

    /// <summary>
    /// A tried and tested PagedList implementation
    /// </summary>
    public class PagedList<T> : List<T>, IPagedList<T>
    {
        //public PagedList(IEnumerable<T> source, int pageIndex, int pageSize) :
        //    this(source.GetPage(pageIndex, pageSize), pageIndex, pageSize, source.Count()) { }

        public PagedList(IEnumerable<T> source, int pageIndex, int pageSize, int totalCount)
        {
            //Ensure.Argument.NotNull(source, "source");

            this.TotalCount = totalCount;
            this.TotalPages = totalCount / pageSize;

            if (totalCount % pageSize > 0)
                TotalPages++;

            this.PageSize = pageSize;
            this.PageIndex = pageIndex;

            this.AddRange(source.ToList());
        }

        public int PageIndex { get; private set; }
        public int PageSize { get; private set; }
        public int TotalCount { get; private set; }
        public int TotalPages { get; private set; }

        public bool HasPreviousPage { get { return (PageIndex > 0); } }
        public bool HasNextPage { get { return (PageIndex + 1 < TotalPages); } }
    }

    public class EnumerableConverter : Newtonsoft.Json.JsonConverter
    {
        private IEnumerable<string> Types { get; set; }
        private bool IsCamelCase { get; set; }

        public EnumerableConverter(IEnumerable<string> types)
            : this(types, true)
        {
        }

        public EnumerableConverter(IEnumerable<string> types, bool isCamelCase)
        {
            if (types == null) throw new ArgumentNullException("types");
            Types = types;
            IsCamelCase = isCamelCase;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            writer.WriteStartObject();
            var foundInnerEnumerable = false;
            foreach (var property in value.GetType().GetProperties()) {
                try {
                    var propVal = property.GetValue(value, null);
                    foundInnerEnumerable |= propVal is IEnumerable;
                    writer.WritePropertyName(NameFor(property.Name));
                    serializer.Serialize(writer, propVal);
                }
                catch (System.Reflection.TargetParameterCountException) { 
                    // Ignore properties such as Item on List<T>
                }
            }
            if (!foundInnerEnumerable) {
                writer.WritePropertyName(NameFor("Items"));
                writer.WriteStartArray();
                foreach (var item in (IEnumerable)value) {
                    serializer.Serialize(writer, item);
                }
                writer.WriteEndArray();
            }
            writer.WriteEndObject();
        }

        private string NameFor(string value)
        {
            if (!IsCamelCase) return value;
            return value[0].ToString().ToLowerInvariant() + value.Substring(1);
        }

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

        public override bool CanConvert(Type objectType)
        {
            return Types.Any(t => objectType.FullName.StartsWith(t));
        }
    }

}

这篇关于在实现IEnumerable的类上序列化自定义属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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