比AutoMapper更强的 表达式通用映射器 ExpressionGenericMapper

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace Guma.StudyNotes.ExpressionExtend.Utils
{
    /// <summary>
    /// 表达式通用映射器
    /// </summary>
    /// <remarks>@Auth: Guma;@Website: www.1995v.com</remarks>
    /// <typeparam name="TIn">传入类型:不能为集合类型,会引发 ParameterCannotCollectionException 异常</typeparam>
    /// <typeparam name="TOut">返回类型:不能为集合类型,会引发 ParameterCannotCollectionException 异常</typeparam>
    public static class ExpressionGenericMapper<TIn, TOut> where TIn : class, new() where TOut : class, new()
    {
        private static Func<TIn, TOut> _func = null;
        static ExpressionGenericMapper()
        {
            if (typeof(TIn).Namespace.Contains("System.Collections"))
            {
                throw new ParameterCannotCollectionException();
            }
            else
            {  
                ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
                List<MemberBinding> memberBindingList = new List<MemberBinding>();

                foreach (var item in typeof(TOut).GetProperties())
                {
                    if (item.SetMethod != null)
                    {
                        MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                        MemberBinding memberBinding = Expression.Bind(item, property);
                        memberBindingList.Add(memberBinding);
                    }
                }

                foreach (var item in typeof(TOut).GetFields())
                {
                    MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }

                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
                Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
                {
                    parameterExpression
                });

                _func = lambda.Compile();
            }
        }

        #region Overloading Methods

        public static TOut Trans(TIn t)
        {
            return _func(t);
        }

        public static List<TOut> Trans(List<TIn> t)
        {
            List<TOut> lstTout = new List<TOut>();

            foreach (var item in t)
            {
                lstTout.Add(_func(item));
            }

            return lstTout;
        }

        public static Dictionary<T, TOut> Trans<T>(Dictionary<T, TIn> t)
        {
            Dictionary<T, TOut> mapTout = new Dictionary<T, TOut>();

            foreach (var item in t)
            {
                mapTout.Add(item.Key, _func(item.Value));
            }

            return mapTout;
        }

        public static Stack<TOut> Trans(Stack<TIn> t)
        {
            Stack<TOut> stackout = new Stack<TOut>();

            foreach (var item in t)
            {
                stackout.Push(_func(item));
            }

            return stackout;
        }

        public static Queue<TOut> Trans(Queue<TIn> t)
        {
            Queue<TOut> queuekout = new Queue<TOut>();

            foreach (var item in t)
            {
                queuekout.Enqueue(_func(item));
            }

            return queuekout;
        }

        public static ConcurrentBag<TOut> Trans(ConcurrentBag<TIn> t)
        {
            ConcurrentBag<TOut> bagout = new ConcurrentBag<TOut>();

            foreach (var item in t)
            {
                bagout.Add(_func(item));
            }

            return bagout;
        }

        public static ConcurrentDictionary<T, TOut> Trans<T>(ConcurrentDictionary<T, TIn> t)
        {
            ConcurrentDictionary<T, TOut> mapout = new ConcurrentDictionary<T, TOut>();

            foreach (var item in t)
            {
                mapout.TryAdd(item.Key, _func(item.Value));
            }

            return mapout;
        }

        public static ConcurrentQueue<TOut> Trans(ConcurrentQueue<TIn> t)
        {
            ConcurrentQueue<TOut> queueout = new ConcurrentQueue<TOut>();

            foreach (var item in t)
            {
                queueout.Enqueue(_func(item));
            }

            return queueout;
        }

        public static ConcurrentStack<TOut> Trans(ConcurrentStack<TIn> t)
        {
            ConcurrentStack<TOut> stackout = new ConcurrentStack<TOut>();

            foreach (var item in t)
            {
                stackout.Push(_func(item));
            }

            return stackout;
        }

        #endregion

        #region ExceptionList

        class ParameterCannotCollectionException : ApplicationException
        {
            private const string _message = "当前泛型不能为集合类型,请使用集合方式的重载方法";

            public ParameterCannotCollectionException(string message = _message) : base(message) { }
        }

        #endregion
    }
}

 

posted @ 2021-03-01 10:31  Torylon  阅读(119)  评论(0编辑  收藏  举报