问题
I have an ASP .Net core application. I am simply trying to have my AutoMapper configure to convert a string comma delimited into a list of strings as per this configuration:
configuration.CreateMap<Job, JobDto>()
.ForMember(dto => dto.Keywords, options => options.MapFrom(entity => entity.Keywords.Split(',').ToList()))
For some reason it does not get compiled and give me the following error:
An expression tree may not contain a call or invocation that uses optional argument
I can't see why I am getting this error. I am pretty sure that I have done that in my other projects before without any such error.
回答1:
This is completely true.
Error is raised because expression tree being created is about to contain some more complex logic, like .Split(',').ToList()
, which is not an accessible property or method, only top-level reflected object properties and methods are supported (like in class MemberInfo
).
Property chaining, deep-calls (.obj1property.obj2property), extension methods are not supported by the expression trees, like in this .ToList()
call.
My solution was like this:
// Execute a custom function to the source and/or destination types after member mapping
configuration.CreateMap<Job, JobDto>()
.AfterMap((dto,jobDto)=>jobDto.Keywords = dto.Keywords.Split(',').ToList());
回答2:
As error says, Split function has an optional parameter. The full signature of it is as this (options is optional)
public string[] Split(string separator, StringSplitOptions options = StringSplitOptions.None)
As you are trying to use a function with default value inside an expression tree, it gives you the error. To Fix it, easy, just pass on optional parameters by yourself. ( StringSplitOptions.None ) So, simply change it to this:
entity.Keywords.Split(',' , StringSplitOptions.None).ToList()
回答3:
I had the same problem. I do not know if it is an issue or not. Anyway, I found a workaround.
CreateMap<Category, GetCategoryRest>()
.ForMember(dest => dest.Words,
opt => opt.MapFrom(src => ToWordsList(src.Words)));
private static List<string> ToWordsList(string words)
{
return string.IsNullOrWhiteSpace(words) ? new List<string>() : words.Split(",").ToList();
}
It is guaranteed that AutoMapper
has always a List
. Still, I'm confused. In my Startup.cs
I define that AutoMapper
allows null values for list.
Mapper.Initialize(cfg => {
cfg.AllowNullCollections = true;
}
Category.Words
is a string
.
GetCategoryRest.Words
is a List<string>
AutoMapper Version: 8.1.1, AutoMapper.Microsoft.DependencyInjection: 6.1.1
回答4:
Use .AfterMap
CreateMap<src, dto>()
.ForMember(src =>src.Categories,options=> options.Ignore())
.AfterMap((src, dto) => { dto.Categories.AddRange(src.Categories.Split(",").ToList()); })
.ReverseMap()
.ForMember(src => src.Categories, option => option.MapFrom(dto => string.Join(",", dto.Categories)));
来源:https://stackoverflow.com/questions/54858116/using-string-split-in-automapper-issue