2015-10-17 30 views
2

如何映射使用AutoMapper 下面的類沒有明確地表明所有成員映射:使用翻譯類如何實現自定義命名解析爲AutoMapper

public class Destination 
{ 
    public string Imie { get; set; } 
    public string Nazwisko { get; set; } 
    ... (huge amount of other properties) 
} 

public class Source 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    ... (huge amount of other properties) 
} 

var translations = new Dictionary<string, string>() 
{ 
    { "FirstName", "Imie" }, 
    { "LastName", "Nazwisko" }, 
    ... (huge amount of other translations) 
} 
+0

你必須指定explicilty因爲名字都在這兩種類型的 –

+0

你可能想看看完全不同:[用法AutoMapper當屬性名稱不同](http://stackoverflow.com/questions/2186160/usage-of-automapper-when-property-names-are-different?rq=1)。具體來說,你應該創建自己的[INamingConvention](http://stackoverflow.com/questions/3866369/how-do-i-get-automapper-to-deal-with-a-custom-naming-convention) –

回答

0

一種方法是使用Reflection

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); 
+0

謝謝爲後。但是你的解決方案不使用AutoMapper。 – MaciejLisCK

2

這裏是你可以怎麼做。

考慮以下方法:

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)作爲屬性類型。

我們可以通過使用反射來獲取屬性的類型,然後動態調用MapFrom方法和適當的TMember類型參數來解決此問題。

0

感謝@雅各布 - 馬薩德答案,我有此解決方案:

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); 
+1

我沒有簡單地使用'string'的原因是我假設你的類可能具有其他類型的屬性(例如'int') –

+0

例如,在同一個類中,可以有一些'string'類型的屬性和其他一些'int'類型的屬性 –

相關問題