c# - Unity - 使用接口(interface)参数注册通用类型

标签 c# generics unity-container

我正在尝试通过遵循此 article 来实现 CQRS ,我的一切正常,但我不知道如何在 Unity 中注册所有 IQueryHandler 类型。

我有以下类(class):

// query
public class GetTitleByIdQuery : IQuery
{
    public int Id { get; set; }
}

//result
public class GetTitleByIdResult : IQueryResult
{
    public int Id { get; set; }
    public string Description { get; set; }
}

// handler
public class GetTitleById : IQueryHandler<GetTitleByIdQuery, GetTitleByIdResult>
{
    public async Task<GetTitleByIdResult> Retrieve(GetTitleByIdQuery query)
    {
        var context = new MyContext();
        return await context.Titles.Where(i => i.Id == query.id).Select(i => new GetTitleByIdResult {Id = i.Id, Description = i.Description}).SingleAsync();
    }
}

如果我明确注册类型,它会得到正确解析,例如

container.RegisterType<IQueryHandler<GetTitleByIdQuery, GetTitleByIdResult>, GetTitleById>();

解决方式:

GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IQueryHandler<TParameter, TResult>));

但是这意味着我必须手动注册每种类型,理想情况下我想做类似的事情:

container.RegisterTypes(
     AllClasses.FromLoadedAssemblies().Where(type => typeof(IQueryHandler<,>).IsAssignableFrom(type)),
            WithMappings.FromAllInterfaces, WithName.TypeName, WithLifetime.Transient);

当我尝试这样做时,没有任何类型被注册,我认为这是因为它们不可分配,例如,这是无效的语法:

IQueryHandler<IQuery, IQueryResult> test = new GetTitleById();

原文章的作者似乎可以使用Ninject来做到这一点,在Unity中也可以吗?

最佳答案

您可以添加扩展方法 RegisterAllTypesForOpenGeneric,例如:

 container.RegisterAllTypesForOpenGeneric(typeof(IQueryHandler<,>), Assembly.GetAssembly(typeof(GetTitleById )));

与:

public static class UnityExtensions
{
    public static void RegisterAllTypesForOpenGeneric(this IUnityContainer container, Type openGenericType, Assembly targetAssembly)
    {
        if (!openGenericType.IsGenericTypeDefinition)
            throw new ArgumentException("typeToRegister must be an open generic type", "typeToRegister");

        foreach (Type type in targetAssembly.GetExportedTypes())
        {
            if (openGenericType.IsInterface)
                RegisterInterfaceTypes(container, openGenericType, type, type);
            else
                RegisterBaseTypes(container, openGenericType, type, type);
        }
    }

    private static void RegisterInterfaceTypes(IUnityContainer container, Type openGenericType, Type targetType, Type typeToRegister)
    {
        foreach (Type interfaceType in targetType.GetInterfaces())
            if (interfaceType.IsGenericType && !interfaceType.ContainsGenericParameters && openGenericType.IsAssignableFrom(interfaceType.GetGenericTypeDefinition()))
                container.RegisterType(interfaceType, typeToRegister);
    }

    private static void RegisterBaseTypes(IUnityContainer container, Type openGenericType, Type targetType, Type typeToRegister)
    {
        if (targetType.BaseType != null && targetType.BaseType != typeof(object))
            if (targetType.BaseType.IsGenericType && openGenericType.IsAssignableFrom(targetType.BaseType.GetGenericTypeDefinition()))
                container.RegisterType(targetType.BaseType, typeToRegister);
            else
                RegisterBaseTypes(container, openGenericType, targetType.BaseType, typeToRegister);
    }
}

来源:http://www.danderson00.com/2010/09/automatically-register-implementors-of.html

关于c# - Unity - 使用接口(interface)参数注册通用类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30192962/

相关文章:

c# - Unity【依赖】注入(inject)与继承

javascript - MVC foreach循环唯一id C#

使用生成器或类似的 Java 模板类?

C# Linq - 延迟执行

java - 这段代码如何继承父类的内部类?

Java generics - 通配符的目的除了下限?

c# - 使用 Unity 注册 Mock 对象的问题

.net - 将DI实践应用于遗留应用程序系统

c# - 更新 ZipArchive 中的文件

c# - 什么是更好的做法?使用数据集或数据库