我有两个非常简单的对象:
public class CategoryDto
{
public string Id { get; set; }
public string MyValueProperty { get; set; }
}
public class Category
{
public string Id { get; set; }
[MapTo("MyValueProperty")]
public string Key { get; set; }
}
使用AutoMapper将Category
映射到CategoryDto
时,我希望以下行为:
应该像往常一样映射属性,但具有MapTo
属性的属性除外。在这种情况下,我必须读取Attribute的值来查找target属性。 source属性的值用于在destination属性中查找要注入的值(借助字典)。一个例子总是好于1000字......
示例:
Dictionary<string, string> keys =
new Dictionary<string, string> { { "MyKey", "MyValue" } };
Category category = new Category();
category.Id = "3";
category.Key = "MyKey";
CategoryDto result = Map<Category, CategoryDto>(category);
result.Id // Expected : "3"
result.MyValueProperty // Expected : "MyValue"
Key
属性映射到MyValueProperty
(通过MapTo
属性),分配的值是&#34; MyValue&#34;,因为源属性值是&#34;的myKey&#34;它被映射(通过字典)到&#34; MyValue&#34;。
使用AutoMapper可以实现吗?我当然需要一个适用于每个对象的解决方案,而不仅仅是Category / CategoryDto。
答案 0 :(得分:8)
我终于(经过这么多小时!!!!)找到了解决方案。 我与社区分享这个;希望它会帮助别人...
编辑:请注意,它现在更加简单(AutoMapper 5.0+),您可以像我在这篇文章中回答的那样:How to make AutoMapper truncate strings according to MaxLength attribute?
public static class Extensions
{
public static IMappingExpression<TSource, TDestination> MapTo<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
Type sourceType = typeof(TSource);
Type destinationType = typeof(TDestination);
TypeMap existingMaps = Mapper.GetAllTypeMaps().First(b => b.SourceType == sourceType && b.DestinationType == destinationType);
string[] missingMappings = existingMaps.GetUnmappedPropertyNames();
if (missingMappings.Any())
{
PropertyInfo[] sourceProperties = sourceType.GetProperties();
foreach (string property in missingMappings)
{
foreach (PropertyInfo propertyInfo in sourceProperties)
{
MapToAttribute attr = propertyInfo.GetCustomAttribute<MapToAttribute>();
if (attr != null && attr.Name == property)
{
expression.ForMember(property, opt => opt.ResolveUsing(new MyValueResolve(propertyInfo)));
}
}
}
}
return expression;
}
}
public class MyValueResolve : IValueResolver
{
private readonly PropertyInfo pInfo = null;
public MyValueResolve(PropertyInfo pInfo)
{
this.pInfo = pInfo;
}
public ResolutionResult Resolve(ResolutionResult source)
{
string key = pInfo.GetValue(source.Value) as string;
string value = dictonary[key];
return source.New(value);
}
}
答案 1 :(得分:0)
使用IValueResolver和ResolveUsing()方法的实现应该相当简单。你基本上只需要为解析器提供一个接受属性信息的构造函数(或者如果你想要接受一个lambda表达式并解析类似于How to get the PropertyInfo of a specific property?的属性信息。虽然我还没有测试过它我自己想象以下内容会起作用:
AutoMapper.Mapper.CreateMap<Category, CategoryDto>()
.ForMember(
dest => dest.Value,
opt => opt.ResolveUsing(
src =>
new PropertyBasedResolver(typeof(Category.Key) as PropertyInfo).Resolve(src)));
然后设置您需要执行的映射:
date
当然这是一个非常糟糕的lamda,我建议你通过让你的属性解析器根据属性/属性信息确定它应该查看的源对象的属性来清理它,这样你就可以通过一个干净的将新的PropertyBasedResolver(属性)放入ResolveUsing()中,但希望这足以让您走上正确的轨道。
答案 2 :(得分:0)
让我们假设我有以下课程
public class foo
{
public string Value;
}
public class bar
{
public string Value1;
public string Value2;
}
您可以将lambda传递给ResolveUsing:
.ForMember(f => f.Value, o => o.ResolveUsing(b =>
{
if (b.Value1.StartsWith("A"));)
{
return b.Value1;
}
return b.Value2;
}
));