-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
I've having an issue where I have a mapping using MapFrom, where the expression passes the object being mapped into a method call. I'm not quite sure how to explain this properly, but I've managed to create a set of tests that highlight the issue.
I've tested this against the MyGet alpha version of AutoMapper.
So say I have the following classes:
public interface IDateProvider
{
DateTime CurrentRestaurantTime(Restaurant restaurant);
}
public class Result
{
public Booking Booking { get; set; }
}
public class Restaurant
{
}
public class Booking
{
public Restaurant Restaurant { get; set; }
public int? CalculateTotal(DateTime currentTime)
{
return null;
}
}
public class ResultDto
{
public BookingDto Booking { get; set; }
}
public class BookingDto
{
public int? Total { get; set; }
}
And I create the following mapping:
var mapperConfiguration = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Result, ResultDto>();
cfg.CreateMap<Booking, BookingDto>()
.ForMember(d => d.Total,
o => o.MapFrom(b => b.CalculateTotal(_dateProvider.CurrentRestaurantTime(b.Restaurant))));
});
When I try to map from a Result to a ResultDto, I get the following exception:
System.InvalidOperationException : variable 'src' of type 'AutoMapperRepros.Class1+Booking' referenced from scope '', but it is not defined
at System.Linq.Expressions.Compiler.VariableBinder.Reference(ParameterExpression node, VariableStorageKind storage)
at System.Linq.Expressions.Compiler.VariableBinder.VisitParameter(ParameterExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitTry(TryExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.Compiler.VariableBinder.VisitBlock(BlockExpression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.Compiler.VariableBinder.VisitBlock(BlockExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitTry(TryExpression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.Compiler.VariableBinder.VisitBlock(BlockExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.Compiler.VariableBinder.VisitBlock(BlockExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.Compiler.VariableBinder.VisitBlock(BlockExpression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.Compiler.VariableBinder.VisitBlock(BlockExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitTry(TryExpression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.Compiler.VariableBinder.VisitBlock(BlockExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.Compiler.VariableBinder.VisitLambda[T](Expression`1 node)
at System.Linq.Expressions.Compiler.VariableBinder.Bind(LambdaExpression lambda)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator)
at AutoMapper.MapperConfiguration.CreateMapperFuncs(MapRequest mapRequest)
at AutoMapper.LockingConcurrentDictionary`2.<>c__DisplayClass2_1.<.ctor>b__1()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at AutoMapper.MapperConfiguration.GetUntypedMapperFunc(MapRequest mapRequest)
at AutoMapper.Mapper.AutoMapper.IMapper.Map[TDestination](Object source)
at AutoMapperRepros.Class1.FailingMapping() in C:\Users\AdamConnelly\github.com\adam-resdiary\AutoMapperRepros\AutoMapperRepros\Class1.cs:line 40
I can work around this by extracting the lambda into a separate method instead of writing it inline.
Here's a link to a gist with one test that fails, highlighting the issue, and another test that passes showing the workaround: https://gist.github.com/adam-resdiary/137396c167c03cda15d42816d953461b