Automapper扩展方法

问题描述

系统中实现了一个自定义的PagedList

/// <summary>
    /// Paged list interface
    /// </summary>
    public interface IPagedList
    {
        int PageIndex { get; }
        int PageSize { get; }
        int TotalCount { get; }
        int TotalPages { get; }
        bool HasPreviousPage { get; }
        bool HasNextPage { get; }
    }

    /// <summary>
    /// Paged list interface
    /// </summary>
    public interface IPagedList<T> : IList<T>, IPagedList
    {
    }


/// <summary>
    /// Paged list
    /// </summary>
    /// <typeparam name="T">T</typeparam>
    [Serializable]
    public class PagedList<T> : List<T>, IPagedList<T> 
    {
        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="source">source</param>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        public PagedList(IQueryable<T> source, int pageIndex, int pageSize)
        {
            int total = source.Count();
            this.TotalCount = total;
            this.TotalPages = total / pageSize;

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

            this.PageSize = pageSize;
            this.PageIndex = pageIndex;
            this.AddRange(source.Skip(pageIndex * pageSize).Take(pageSize).ToList());
        }

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="source">source</param>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        public PagedList(IList<T> source, int pageIndex, int pageSize)
        {
            TotalCount = source.Count();
            TotalPages = TotalCount / pageSize;

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

            this.PageSize = pageSize;
            this.PageIndex = pageIndex;
            this.AddRange(source.Skip(pageIndex * pageSize).Take(pageSize).ToList());
        }

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="source">source</param>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <param name="totalCount">Total count</param>
        public PagedList(IEnumerable<T> source, int pageIndex, int pageSize, int totalCount)
        {
            TotalCount = totalCount;
            TotalPages = TotalCount / pageSize;

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

            this.PageSize = pageSize;
            this.PageIndex = pageIndex;
            this.AddRange(source);
        }

        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); }
        }
    }

转换失败,AutoMapper可不认识PagedList

 [TestMethod]
        public void MapTest2()
        {
            Mapper.CreateMap<User, UserViewModel>();

            var userList = new List<User>()
            {
                new User() {Name = "Name1", UserId = "UserId1"},
                new User() {Name = "Name2", UserId = "UserId2"},
                new User() {Name = "Name3", UserId = "UserId3"},
                new User() {Name = "Name4", UserId = "UserId4"},
                new User() {Name = "Name5", UserId = "UserId5"},
                new User() {Name = "Name6", UserId = "UserId6"},
                new User() {Name = "Name7", UserId = "UserId7"},
            };

            var pagedList = new PagedList<User>(userList, 0, 5);

            
            Mapper.Map<PagedList<User>, PagedList<UserViewModel>>(pagedList);//Exception
            
        }

解决方案

 /// <summary>
    /// The collection extensions.
    /// </summary>
    public static class ObjectExtensions
    {
        private static readonly MethodInfo mapMethod;
        private static readonly ConcurrentDictionary<Tuple<Type, Type>, Tuple<MethodInfo, Type>> methodsMapper = new ConcurrentDictionary<Tuple<Type, Type>, Tuple<MethodInfo, Type>>();

        static ObjectExtensions()
        {
            mapMethod = (typeof(Mapper)).GetMethods().FirstOrDefault(_ => _.Name == "Map" && _.GetParameters().Length == 1);
        }

        public static T MapTo<T>(this IPagedList tList) where T : class
        {
            var totalCount = tList.TotalCount;
            var pageIndex = tList.PageIndex;
            var pageSize = tList.PageSize;


            var t = methodsMapper.GetOrAdd(new Tuple<Type, Type>(tList.GetType(), typeof(T)), _ =>
            {
                var targetGenericArguments = typeof(T).GenericTypeArguments[0];
                var targetGenericArgumentsIEnumerableType = typeof(IEnumerable<>).MakeGenericType(targetGenericArguments);
                return new Tuple<MethodInfo, Type>(mapMethod.MakeGenericMethod(targetGenericArgumentsIEnumerableType),
                    typeof(PagedList<>).MakeGenericType(targetGenericArguments));
            });
            var rtn2 = t.Item1.Invoke(null, new object[] { tList });
            var o2 = Activator.CreateInstance(t.Item2, rtn2, pageIndex, pageSize, totalCount) as T;
            return o2;
        }

        public static T MapTo<T>(this object o) where T : class
        {
            //way1
            //var mapMethod = (typeof(Mapper)).GetMethods().FirstOrDefault(_ => _.Name == "Map" && _.GetParameters().Length == 1 && _.GetGenericArguments().Length == 2 );
            //var m2 =  mapMethod.MakeGenericMethod(o.GetType(), typeof (T));
            //return m2.Invoke(null, new[] { o }) as T;

            //way2
            return Mapper.Map<T>(o);
        }

        public static void MapTo<S,T>(this S o,T t) where T : class
        {
            Mapper.Map(o,t);
        }
    }

测试通过

[TestMethod]
        public void MapTest2()
        {
            Mapper.CreateMap<User, UserViewModel>();

            var userList = new List<User>()
            {
                new User() {Name = "Name1", UserId = "UserId1"},
                new User() {Name = "Name2", UserId = "UserId2"},
                new User() {Name = "Name3", UserId = "UserId3"},
                new User() {Name = "Name4", UserId = "UserId4"},
                new User() {Name = "Name5", UserId = "UserId5"},
                new User() {Name = "Name6", UserId = "UserId6"},
                new User() {Name = "Name7", UserId = "UserId7"},
            };

            var pagedList = new PagedList<User>(userList, 0, 5);
            var vmPagedList = pagedList.MapTo<PagedList<UserViewModel>>();
            Assert.IsTrue(vmPagedList.TotalPages == 2 
                && vmPagedList.PageSize == 5
                && vmPagedList.PageIndex == 0
                );

        }

 

 

总结

运行时动态获取泛型参数并执行Mapper.Map<IEnumerable<TSource>, IEnumerable<TDestination>>,并且使用ConcurrentDictionary缓存MethodInfo提高性能。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。