自动注册所有泛型接口的实现类

6

我的当前注册码:

Assembly web = Assembly.Load("MyAssembly");
types.AddRange(web.GetTypes());
//etc.

foreach (var theInterface in types.Where(t => t.IsInterface))
{
    var assignableType = types.Where(t => theInterface.IsAssignableFrom(t) && t != theInterface);
    foreach (var type in assignableType)
    {
        container.RegisterType(theInterface, type);
    }
}

我的通用接口及其实现:

public interface IDomainEventHandler<in T>
{
    void Handle(T message);
}

public class DomainEventHandler1 : IDomainEventHandler<PhilTest1>
{
    public void Handle(PhilTest1 message)
    {
        throw new System.NotImplementedException();
    }
}

public class DomainEventHandler2 : IDomainEventHandler<PhilTest2>
{
    public void Handle(PhilTest2 message)
    {
        throw new System.NotImplementedException();
    }
}

public class DomainEventHandler3 : IDomainEventHandler<PhilTest2>
{
    public void Handle(PhilTest2 message)
    {
        throw new System.NotImplementedException();
    }
}

public class PhilTest1
{

}

public class PhilTest2
{

}

以下是我解决问题的简化版本:

IEnumerable<IDomainEventHandler<PhilTest2>> listeners = Container.ResolveAll<IDomainEventHandler<PhilTest2>>();
IEnumerable<IDomainEventHandler<PhilTest1>> listeners2 = Container.ResolveAll<IDomainEventHandler<PhilTest1>>();

这段代码无法实现 - 当解决后,listeners和listeners2都为空。这是预料中的结果。

在Windsor中,我可以这样做:

container.Register(AllTypes.FromAssemblyNamed("MyAssembly").BasedOn(typeof(IDomainEventHandler<>)).WithService.Base());

我该如何在Unity中注册所有IDomainEventHandler实例?如果可能的话,我希望保留现有的注册代码不变。

1个回答

5
有点痛苦,但是我最终通过搜索和调试拼凑出来了:
注册:
    IEnumerable<Type> handlers = types.Where(t => IsAssignableToGenericType(t, typeof(IDomainEventHandler<>)) && !t.IsInterface);

    foreach (var handler in handlers)
    {
        container.AddNewExtension<OpenGenericExtension>()
                    .Configure<IOpenGenericExtension>()
                    .RegisterClosedImpl(typeof (IDomainEventHandler<>), handler);
    }

IsAssignableToGenericType method:

    private static bool IsAssignableToGenericType(Type givenType, Type genericType)
    {
        var interfaceTypes = givenType.GetInterfaces();

        foreach (var it in interfaceTypes)
        {
            if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
                return true;
        }

        if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
            return true;

        Type baseType = givenType.BaseType;
        if (baseType == null) return false;

        return IsAssignableToGenericType(baseType, genericType);
    }

还有一个扩展。请注意,如果我没有使用名称进行注册,那么只会保留一种类型的注册。我认为这是设计上的原因?

public interface IOpenGenericExtension : IUnityContainerExtensionConfigurator
{
    void RegisterClosedImpl(Type openGenericInterface, Type closedType);
}

public class OpenGenericExtension : UnityContainerExtension, IOpenGenericExtension
{
    protected override void Initialize() {}

    public void RegisterClosedImpl(Type openGenericInterface, Type closedType)
    {
        closedType.GetInterfaces().Where(x => x.IsGenericType)
                  .Where(x => x.GetGenericTypeDefinition() == openGenericInterface)
                  .ToList()
                  .ForEach(x => Container.RegisterType(x, closedType, closedType.Name));
    }
}

3
谢谢你。相比其他IoC容器,我感觉Unity有些单薄。 - will
幸运的是,Unity现在通过container.RegisterTypes方法实现了基于约定的注册。而且这个方法还支持泛型!太棒了! - MichaC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接