你的位置:首页 > ASP.net教程

[ASP.net教程]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提高性能。