如何为AutoMapper实现自定义命名解析器
本文关键字:自定义 AutoMapper 实现 | 更新日期: 2023-09-27 18:18:05
如何使用AutoMapper 映射下面的类而不显式指示所有成员映射:
public class Source
{
public string FirstName { get; set; }
public string LastName { get; set; }
... (huge amount of other properties)
}
类:
public class Destination
{
public string Imie { get; set; }
public string Nazwisko { get; set; }
... (huge amount of other properties)
}
使用翻译类:
var translations = new Dictionary<string, string>()
{
{ "FirstName", "Imie" },
{ "LastName", "Nazwisko" },
... (huge amount of other translations)
}
你可以这样做。
考虑以下方法:
public void CreateMapBasedOnDictionary<TSource, TDestination>(IDictionary<string, string> mapping_dictionary)
{
var mapping_expression = AutoMapper.Mapper.CreateMap<TSource, TDestination>();
foreach (var kvp in mapping_dictionary)
{
string source_property_name = kvp.Key;
string destination_property_name = kvp.Value;
Type member_type = typeof (TSource).GetProperty(source_property_name).PropertyType;
mapping_expression = mapping_expression.ForMember(destination_property_name, x =>
{
typeof (IMemberConfigurationExpression<TSource>)
.GetMethod("MapFrom", new []{typeof(string)})
.MakeGenericMethod(member_type)
.Invoke(x, new[] { source_property_name });
});
}
}
然后你可以这样使用:
var translations = new Dictionary<string, string>()
{
{"FirstName", "Imie"},
{"LastName", "Nazwisko"},
};
CreateMapBasedOnDictionary<Source, Destination>(translations);
Source src = new Source()
{
FirstName = "My first name",
LastName = "My last name"
};
var dst = AutoMapper.Mapper.Map<Destination>(src);
以下是CreateMapBasedOnDictionary
方法的解释:
AutoMapper已经重载了ForMember
,允许您按名称指定目标属性。我们在这里很好。
它也有一个超载的MapFrom
,允许您指定名称的源属性。然而,这个重载的问题是,它需要属性类型的泛型参数(TMember
)。
我们可以通过使用反射来获取属性的类型,然后使用适当的TMember
类型参数动态调用MapFrom
方法来解决这个问题。
一种方法是使用反射:
private TDestination Map<TSource, TDestination>(TSource source, Dictionary<string, string> mapData)
where TSource : class
where TDestination : class, new()
{
if (source == null) return null;
if (mapData == null) mapData = new Dictionary<string, string>();
TDestination destination = new TDestination();
PropertyInfo[] sourceProperties = typeof(TSource).GetProperties();
foreach (PropertyInfo property in sourceProperties)
{
string destPropertyName = mapData.ContainsKey(property.Name) ? mapData[property.Name] : property.Name;
PropertyInfo destProperty = typeof(TDestination).GetProperty(destPropertyName);
if (destProperty == null) continue;
destProperty.SetValue(destination, property.GetValue(source));
}
return destination;
}
你可以这样调用它:
Destination mapped = Map<Source, Destination>(source, translations);
感谢@yacoub-massad的回答,我做了这个解决方案:
var map = Mapper.CreateMap<Source, Destination>();
var sourceProperties = typeof(Source).GetProperties();
foreach (var sourceProperty in sourceProperties)
{
var sourcePropertyName = sourceProperty.Name;
var destinationPropertyName = translations[sourceProperty.Name];
map.ForMember(destinationPropertyName, mo => mo.MapFrom<string>(sourcePropertyName));
}
var src = new Source() { FirstName = "Maciej", LastName = "Lis" };
var dest = Mapper.DynamicMap<Destination>(src);