简体   繁体   English

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

[英]System.InvalidOperationException: 'Code supposed to be unreachable'

after some discussion with AutoMapper team, they recommended me to put my question here. 与AutoMapper团队讨论后,他们建议我在这里提出问题。

In short, if I map the expressions that I need using 简而言之,如果我映射需要使用的表达式

MapExpression<T>(source)

it works perfectly fine (considering using the AutoMapper.Extensions.ExpressionMapping framework). 它工作得很好(考虑使用AutoMapper.Extensions.ExpressionMapping框架)。

BTW, the authors said me that, even if I try to map using 顺便说一句,即使我尝试使用

Map(object, sourceType, targetType) 

it should work normally but, when I use this method, I have the error as described in the title of this post. 它应该可以正常工作,但是当我使用此方法时,出现了本文标题中所述的错误。

To help, I wrote a full example on how to reproduce the problem as it follows bellow: 为了提供帮助,我写了一个完整的示例,说明如何重现以下问题:

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

Is there anything that I'm missing here? 我在这里想念什么吗? In time: .NET Core 2.2, AutoMapper 9.0, AutoMapper.Extensions.ExpressionMapping 3.0.1 and nothing else. 及时发布:.NET Core 2.2,AutoMapper 9.0,AutoMapper.Extensions.ExpressionMapping 3.0.1,仅此而已。

Thank you. 谢谢。

Author answered and confirmed that it's a bug so, I'm posting the workaround they gave me on their Github page. 作者回答并确认这是一个错误,因此,我在他们的Github页面上发布了他们给我的解决方法。

Here's the link for the issue: https://github.com/AutoMapper/AutoMapper.Extensions.ExpressionMapping/issues/40 这是问题的链接: https : //github.com/AutoMapper/AutoMapper.Extensions.ExpressionMapping/issues/40

We need to create a helper for it, like this: 我们需要为此创建一个助手,如下所示:

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

Then call the extension method like this: 然后像这样调用扩展方法:

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

This will be the workaround until the AutoMapper team fixes it. 这将是解决方法,直到AutoMapper团队对其进行修复。

Hope that this can help someone as it helped me. 希望这能对我有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM