2014-09-10 56 views
0

我有一個接口/類的映射層次結構,它使用基類約束的泛型,我試圖使用基類將它們解析爲它們的派生類。我想知道Autofac是否能以比我目前更好的方式解決這個問題。Autofac - 按基類解析泛型

採取以下結構:

public interface IMapper<T1, T2> 
    where T1 : FooBase 
    where T2 : BarBase 
{ 
    T1 Map(T2 source); 
} 


public class FooBarMapper : IMapper<Foo, Bar> 
{ 
    public Foo Map(Bar source) 
    { 
     return new Foo 
     { 
      blahblah = source.xyz 
     }; 
    } 
} 

接下來,我對「富」,它引用了基本類型A「到」擴展方法,但我想它解析爲一個適當的類型。我目前這樣解決:

public static TDest To<TDest>(this BarBase o) where TDest : FooBase 
{ 
    var genericMapper = typeof(IMapper<,>).MakeGenericType(o.GetType(), typeof(TDest)); 
    object mapper = IocProxy.Container.Resolve(genericMapper); 

    //... etc 
} 

這解決了罰款...但映射只是一個對象。所以我不得不使用反射來點擊「Map」方法。我寧願避免這樣做。 autofac能否以更好的方式做到這一點,以便最終獲得IMapper而不是對象?例如,我寧願做這樣的事情,但autofac顯然不能解決它:

var mapper = IocProxy.Container.Resolve<IMapper<FooBase, TDest>>(); 

回答

0

這個問題的答案有點難看。因爲你不能用1個泛型創建「To」擴展方法,所以你必須使代碼看起來很難看,以便它可以推斷出兩種類型。就像這樣:

public static TDest To<TDest,TSource>(this TSource o) where TDest : new() 
{ 
    var mapper = IocProxy.Container.Resolve<IMapper<TSource, TDest>>(); 
    return mapper.Map(o); 
} 

某處更深下來,我們得到這個醜陋的電話:

var b = a.To<Bar,Foo>(); //<-- to convert it to "Bar" we need to specify both generics 

是的,太醜了!誰真的知道什麼是映射到這裏!除非你明確指定類型,但你知道這些天有些人瘋了。

無論如何,因爲我不喜歡這樣,我開發了一種解決方法來提高可讀性。首先,我創建了一個Map類來包裝我的對象(和我的「To」函數)。這是一個額外的步驟,但作爲一個很好的中介幫助autofac正確解析泛型:

public class Map<TSource> where TSource : new() 
{ 
    public TSource Object { get; set; } 
    public Map(TSource o) 
    { 
     Object = o; 
    } 

    public TDest To<TDest>() 
    { 
     var mapper = IocProxy.Container.Resolve<IMapper<TSource, TDest>>(); 
     return mapper.Map(Object); 
    } 
} 

然後稍微不同的通用擴展方法來獲取映射回(並獲取代碼到我想要的風格):

public static Map<TDest> Map<TDest>(this TDest o) where TDest : new() 
{ 
    return new Map<TDest>(o); 
} 

這確實稍微改變了我想要調用它的方式,但它讀起來也是一樣的。

所以,與其這樣:

foo.To<Bar, Foo>(); 

的代碼看起來像這樣

foo.Map().To<Bar>() 

你甚至可以進一步擴展,並添加和接口Map類,並得到Autofac解決它,但我想這取決於你多久打一次mappers。最後,性能增益可能可以忽略不計。