使用Unity动态注册接口的多个实现(来自AutoMapper的

时间:2018-02-07 19:47:30

标签: c# automapper unity-container

我的代码将动态扫描程序集以实现AutoMapper Profile类的实现,并构建一个映射器以与Unity DI一起使用。最近,我发现需要使用IValueResolver接口。此类需要在其中注入资源依赖项,以便在模型之间执行转换。

我可以在automapper配置中添加一行,强制它使用unity来解析IValueResolvers。

    cfg.ConstructServicesUsing(type => container.Resolve(type));

我无法确定如何动态地为Unity注册通用接口的多个实例。

我可以硬编码

    container.RegisterType<IValueResolver<Class1, Class2, string>,Class1ToClass2ValueResolver>();

但是,我宁愿动态扫描和注册它们。

1 个答案:

答案 0 :(得分:1)

可能有更好的方法,这种方法可能有点天真,可能无法处理所有嵌套类型层次结构或同一通用接口的多个实现,但这种方法适用于已发布的案例。也许可以通过使用一些注册公约功能来清理它。

var resolverTypes = .AppDomain.CurrentDomain.GetAssemblies()
    .Where(a => !a.IsDynamic) // Exclude dynamic assemblies
    .Select(a => a.GetTypes())
    .SelectMany(t => t) // flatten Types for each assembly into one
    .Select(t => t.GetTypeInfo())
    .Where(t => 
        t.ImplementedInterfaces.Any(i =>
            i.IsGenericType && i.GetGenericTypeDefinition()
                             .IsAssignableFrom(typeof(IValueResolver<,,>))))
    .Select(t => new
    {
        Inteface = t.ImplementedInterfaces.First(i =>
            i.IsGenericType && i.GetGenericTypeDefinition()
                             .IsAssignableFrom(typeof(IValueResolver<,,>))),
        Type = t
    });

var container = new UnityContainer();

foreach (var resolverType in resolverTypes)
{
    container.RegisterType(resolverType.Inteface, resolverType.Type);
    var resolver = container.Resolve(typeof(IValueResolver<Class1, Class2, string>));
    Debug.Assert(resolver.GetType() == typeof(Class1ToClass2ValueResolver));
}

努力工作是获得正确的类型: 首先获取所有程序集,排除动态程序集,并展平为可枚举的类型(而不是Enumerable<Type[]>)。接下来只选择具有通用接口的类并匹配开放的通用IValueResolver<,,>接口,并返回具有匹配的封闭通用接口的类型。

一旦我们掌握了这些信息,只需注册从接口到实现的映射即可。在这种情况下,IValueResolver<ClassA, ClassB, string>Class1ToClass2ValueResolver。以下是使用的示例类和接口:

public class Class1 { }

public class Class2 { }

public interface IValueResolver<U, V, W> { }

public class Class1ToClass2ValueResolver : IValueResolver<Class1, Class2, string> { }