返回總目錄
自定義值解析
雖然AutoMapper覆蓋了相當一部分目標成員的對映場景,但是還有 1-5%的目標值需要解析處理一下。很多時候,自定義的值解析是可以放在領域層的領域邏輯。然而,如果該邏輯只是和對映操作有關的話,那它就會應為一些不必要的行為使得源型別很凌亂。這種場合,AutoMapper允許我們為目標成員配置自定義的值解析器。
舉個栗子,有兩個類Source和Destination,定義如下:
public class Source { public int Value1 { get; set; } public int Value2 { get; set; } }
public class Destination { public int Total { get; set; } }
我們想要在對映期間產生一個計算的值,也就是說,在Source到Destination對映的過程中,把Source的兩個屬性值加起來賦給Destination的屬性。由於某些原因,我們不能把這個邏輯放到源型別裡,為了提供一個自定義值解析器,我們首先需要建立一個實現了IValueResolver:
public class MyValueResolver : IValueResolver { public ResolutionResult Resolve(ResolutionResult source) { //TODO:實現邏輯 } }
ResolutionContext包含了當前解析操作的所有上下文資訊,如源型別,源值等等。大多數場合,我們不需要這個更高階的介面。另一種方法,我們可以實現抽象類ValueResolver<TSource, TDestination>:
public class MyValueResolver : ValueResolver<Source, int> { protected override int ResolveCore(Source source) { return source.Value1 + source.Value2; } }
現在,我們已經實現了自己的值解析器,接下來就需要告訴AutoMapper,當解析一個特定的目標成員時,要使用這個自定義的值解析器。有3中方式告訴AutoMapper如何使用自定義解析器,包括:
- ResolveUsing<TValueResolver>
- ResolveUsing(typeof(CustomValueResolver))
- ResolveUsing(aValueResolverInstance)
接下來,我們就開始使用自己的值解析器:
class Program { static void Main(string[] args) { Mapper.CreateMap<Source, Destination>().ForMember(dest => dest.Total, opt => { opt.ResolveUsing<MyValueResolver>(); }); var src = new Source {Value1 = 3, Value2 = 5}; var destObj= Mapper.Map<Destination>(src); Console.WriteLine("destObj.Total={0}", destObj.Total); Console.Read(); } }
雖然目標成員Total沒有任何匹配的源成員,但是我們給它新增了有效配置的自定義解析器,解析器就會對目標成員值的提供負責。
測試成功,結果如下:
自定義建構函式方法
因為我們只提供了自定義的解析器型別給AutoMapper,所以對映引擎會使用反射建立該值解析器的例項。如果我們不想要AutoMapper使用反射建立例項,我們要麼直接提供一個例項,要麼使用ConstruceBy方法來提供一個自定義的建構函式方法:
Mapper.CreateMap<Source, Destination>().ForMember(dest => dest.Total, opt => { opt.ResolveUsing<MyValueResolver>().ConstructedBy(()=>new MyValueResolver()); });
在對映操作期間,AutoMapper不使用反射,直接執行此回撥函式。這在解析器可能需要建構函式引數或者需要通過Ioc容器構建的時候很有用。
這裡不再做演示,有興趣的小夥伴可自行研究。