System.InvalidOperationException:'代码应该无法访问'

时间:2019-08-24 09:00:39

标签: c# asp.net-core automapper

与AutoMapper团队讨论后,他们建议我在这里提出问题。

简而言之,如果我映射需要使用的表达式

MapExpression<T>(source)

它工作得很好(考虑使用AutoMapper.Extensions.ExpressionMapping框架)。

顺便说一句,即使我尝试使用

Map(object, sourceType, targetType) 

它应该可以正常工作,但是当我使用此方法时,出现了本文标题所述的错误。

为提供帮助,我写了一个完整的示例,说明如何重现以下问题:

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

using AutoMapper;
using AutoMapper.Extensions.ExpressionMapping;

namespace AutoMapperExpressionMappingTest
{
    public class PresentationModelPerson
    {
        public string Name { get; set; }
        public DateTime Birthday { get; set; }
    }

    public class ApplicationModelPerson
    {
        public string Name { get; set; }
        public DateTime Birthday { get; set; }
    }

    public class DomainModelPerson
    {
        public string Name { get; set; }
        public DateTime Birthday { get; set; }
    }

    public class PresentationPerson
    {
        private readonly IMapper _mapper;
        public PresentationPerson(IMapper mapper) => _mapper = mapper;

        public  IEnumerable<PresentationModelPerson> List(int take, int skip,
            Expression<Func<IQueryable<PresentationModelPerson>, IOrderedQueryable<PresentationModelPerson>>> orderBy,
            Expression<Func<PresentationModelPerson, bool>> where, IList<Expression<Func<PresentationModelPerson, object>>> includes)
        {
            var applicationTake = take;
            var applicationSkip = skip;

            /*
             * if I map this way the mapping on domain class will fail with the following error:
             * System.InvalidOperationException: 'Code supposed to be unreachable'
             * (there's a reason on my project to use this way)
             */
            dynamic applicationOrderByObject = _mapper.Map(orderBy,
                typeof(Expression<Func<IQueryable<PresentationModelPerson>, IOrderedQueryable<PresentationModelPerson>>>
                ),
                typeof(Expression<Func<IQueryable<ApplicationModelPerson>, IOrderedQueryable<ApplicationModelPerson>>
                >));

            /*
             // if I map this way, it works perfectly //
            var applicationOrderBy =
                _mapper
                    .MapExpression<
                        Expression<Func<IQueryable<ApplicationModelPerson>, IOrderedQueryable<ApplicationModelPerson>>>
                    >(orderBy);
            */

            var applicationWhere = _mapper.MapExpression<Expression<Func<ApplicationModelPerson, bool>>>(where);

            var applicationInclude =
                _mapper.MapExpressionList<Expression<Func<ApplicationModelPerson, object>>>(includes).ToList();


            var applicationPerson = new ApplicationPerson(_mapper);

            applicationPerson.List(applicationTake, applicationSkip, applicationOrderByObject, applicationWhere,
                applicationInclude);

            throw new NotImplementedException();
        }
    }

    public class ApplicationPerson
    {
        private readonly IMapper _mapper;
        public ApplicationPerson(IMapper mapper) => _mapper = mapper;

        public IEnumerable<ApplicationModelPerson> List(int take, int skip,
            Expression<Func<IQueryable<ApplicationModelPerson>, IOrderedQueryable<ApplicationModelPerson>>> orderBy,
            Expression<Func<ApplicationModelPerson, bool>> where, IList<Expression<Func<ApplicationModelPerson, object>>> includes)
        {
            var domainTake = take;
            var domainSkip = skip;

            // this mapping will fail whatever I use this way or _mapper.Map(object, sourceType, targetType) //
            var domainOrderBy =
                _mapper
                    .MapExpression<
                        Expression<Func<IQueryable<DomainModelPerson>, IOrderedQueryable<DomainModelPerson>>>
                    >(orderBy);

            var domainWhere = _mapper.MapExpression<Expression<Func<DomainModelPerson, bool>>>(where);

            var domainInclude =
                _mapper.MapExpressionList<Expression<Func<DomainModelPerson, object>>>(includes).ToList();


            var domainPerson = new DomainPerson(_mapper);

            domainPerson.List(domainTake, domainSkip, domainOrderBy, domainWhere,
                domainInclude);

            throw new NotImplementedException();
        }
    }

    public class DomainPerson
    {
        private readonly IMapper _mapper;
        public DomainPerson(IMapper mapper) => _mapper = mapper;

        public IEnumerable<DomainModelPerson> List(int take, int skip,
            Expression<Func<IQueryable<DomainModelPerson>, IOrderedQueryable<DomainModelPerson>>> orderBy,
            Expression<Func<DomainModelPerson, bool>> where, IList<Expression<Func<DomainModelPerson, object>>> includes)
        {
            throw new NotImplementedException();
        }
    }

    public class ModelProfile : Profile
    {
        public ModelProfile()
        {
            CreateMap<PresentationModelPerson, ApplicationModelPerson>().ReverseMap();
            CreateMap<ApplicationModelPerson, DomainModelPerson>().ReverseMap();
        }
    }

    public class ExpressionProfile : Profile
    {
        public ExpressionProfile()
        {
            CreateMap<Expression<Func<PresentationModelPerson, bool>>,
                Expression<Func<ApplicationModelPerson, bool>>>().ReverseMap();

            CreateMap<Expression<Func<IQueryable<PresentationModelPerson>,
                    IOrderedQueryable<PresentationModelPerson>>>,
                Expression<Func<IQueryable<ApplicationModelPerson>, IOrderedQueryable<ApplicationModelPerson>>>>().ReverseMap();

            CreateMap<IList<Expression<Func<PresentationModelPerson, object>>>,
                IList<Expression<Func<ApplicationModelPerson, object>>>>().ReverseMap();


            CreateMap<Expression<Func<ApplicationModelPerson, bool>>,
                Expression<Func<DomainModelPerson, bool>>>().ReverseMap();

            CreateMap<Expression<Func<IQueryable<ApplicationModelPerson>,
                    IOrderedQueryable<ApplicationModelPerson>>>,
                Expression<Func<IQueryable<DomainModelPerson>, IOrderedQueryable<DomainModelPerson>>>>().ReverseMap();

            CreateMap<IList<Expression<Func<ApplicationModelPerson, object>>>,
                IList<Expression<Func<DomainModelPerson, object>>>>().ReverseMap();
        }
    }

    public class Container
    {
        public IMapper Mapper { get; }

        public Container()
        {
            var mapperConfiguration = new MapperConfiguration(
                configuration =>
                {
                    configuration.AddExpressionMapping();
                    configuration.AddProfile<ModelProfile>();
                    configuration.AddProfile<ExpressionProfile>();
                    configuration.AllowNullCollections = true;
                });

            Mapper = mapperConfiguration.CreateMapper();
            Mapper.ConfigurationProvider.AssertConfigurationIsValid();
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var mapper = new Container().Mapper;

            var presentationPerson = new PresentationPerson(mapper);

            Expression<Func<IQueryable<PresentationModelPerson>, IOrderedQueryable<PresentationModelPerson>>> orderBy = persons =>
                persons.OrderByDescending(person => person.Birthday);

            Expression<Func<PresentationModelPerson, bool>> where = person => !string.IsNullOrEmpty(person.Name);

            presentationPerson.List(1, 100, orderBy, where,
                new List<Expression<Func<PresentationModelPerson, object>>>());
        }
    }
}

这里有什么我想念的吗?及时发布:.NET Core 2.2,AutoMapper 9.0,AutoMapper.Extensions.ExpressionMapping 3.0.1等。

谢谢。

1 个答案:

答案 0 :(得分:1)

作者回答并确认这是一个错误,因此,我正在他们在Github页面上发布他们给我的解决方法。

以下是问题的链接:https://github.com/AutoMapper/AutoMapper.Extensions.ExpressionMapping/issues/40

我们需要为此创建一个助手:

public static class ExpressionMappingHelper
{
    public static LambdaExpression MapExpression(this IMapper mapper, LambdaExpression expression, Type sourceExpressionType, Type destExpressionType)
    {
        if (expression == null)
            return default;

        //This calls public static TDestDelegate MapExpression<TSourceDelegate, TDestDelegate>(this IMapper mapper, TSourceDelegate expression)
        //in AutoMapper.Extensions.ExpressionMapping.MapperExtensions
        return (LambdaExpression)"MapExpression".GetMapExpressionMethod().MakeGenericMethod
        (
            sourceExpressionType,
            destExpressionType
        ).Invoke(null, new object[] { mapper, expression });
    }

    private static MethodInfo GetMapExpressionMethod(this string methodName)
        => typeof(AutoMapper.Extensions.ExpressionMapping.MapperExtensions).GetMethods().Single(m => m.Name == methodName && m.GetGenericArguments().Length == 2);
}

然后像这样调用扩展方法:

        dynamic applicationOrderByObject = _mapper.MapExpression(orderBy,
            typeof(Expression<Func<IQueryable<PresentationModelPerson>, IOrderedQueryable<PresentationModelPerson>>>
            ),
            typeof(Expression<Func<IQueryable<ApplicationModelPerson>, IOrderedQueryable<ApplicationModelPerson>>
            >));

这是解决方法,直到AutoMapper团队对其进行修复为止。

希望这可以像帮助我一样帮助某人。