2014-09-10 109 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。最后,性能增益可能可以忽略不计。