Unity 3.5:通过其开放的通用接口检索具体实现

本文关键字:检索 接口 实现 Unity | 更新日期: 2023-09-27 18:13:13

这篇博文描述了Repository模式的一个很好的替代方案。

https://cuttingedge.it/blogs/steven/pivot/entry.php?id = 92

作者建议使用命令和查询代替存储库。这篇博文描述了在。net/c#中查询部分的实现。

查询和查询处理程序有两个接口:
public interface IQuery<TResult>
{
}
public interface IQueryHandler<TQuery, TResult> where TQuery : IQuery<TResult>
{
    TResult Handle(TQuery query);
}

他还提供了每个例子:

public class FindUsersBySearchTextQuery : IQuery<User[]>
{
    public string SearchText { get; set; }
    public bool IncludeInactiveUsers { get; set; }
}
public class FindUsersBySearchTextQueryHandler
    : IQueryHandler<FindUsersBySearchTextQuery, User[]>
{
    private readonly NorthwindUnitOfWork db;
    public FindUsersBySearchTextQueryHandler(NorthwindUnitOfWork db)
    {
        this.db = db;
    }
    public User[] Handle(FindUsersBySearchTextQuery query)
    {
        return (
            from user in this.db.Users
            where user.Name.Contains(query.SearchText)
            select user)
            .ToArray();
    }
}

查询处理程序可以作为MVC控制器的构造函数参数提供。

public class UserController : Controller
{
    IQueryHandler<FindUsersBySearchTextQuery, User[]> handler;
    public UserController(IQueryHandler<FindUsersBySearchTextQuery, User[]> handler)
    {
        this.handler = handler;
    }
    public View SearchUsers(string searchString)
    {
        var query = new FindUsersBySearchTextQuery
        {
            SearchText = searchString,
            IncludeInactiveUsers = false
        };
        User[] users = this.handler.Handle(query);
        return this.View(users);
    }
}

作者使用依赖注入容器Simple Injector一次性注册所有的IQueryHandler:

container.RegisterManyForOpenGeneric(
    typeof(IQueryHandler<,>),
    typeof(IQueryHandler<,>).Assembly);

我的问题是:我如何在Unity中执行最后一个语句?

我使用Unity 3.5。

我可以手动注册每个QueryHandler,像这样:

container.RegisterType<IQueryHandler<FindUsersBySearchTextQuery, User[]>, 
                       FindUsersBySearchTextQueryHandler>();

这工作得很好,但我不想在每次新的QueryHandler出现时添加新的映射。我想用一个约定来设置所有映射,其中包括未来的QueryHandler。Unity 3.5提供了一个基于约定的注册工作流程,但我不能让它为我的情况工作。我试过了,但不幸的是它没有生成问题中的映射。

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),
    WithMappings.FromMatchingInterface,
    WithName.Default);

Unity 3.5:通过其开放的通用接口检索具体实现

如果您将有许多特定的IQueryHandler<,>实现,而不是一个通用版本,那么您不能使用开放泛型来注册。但是您可以使用反射来查找所有实现并分别注册它们。(这就是RegisterTypes在幕后为你做的事情)。

您在问题中尝试使用RegisterTypes调用,但是您使用了WithMappings.FromMatchingInterface。这将只注册与MyClass : IMyClass命名约定匹配的接口的类(在类名前加上'I')。如果你用WithMappings.FromAllInterfaces注册,你将得到你想要的注册。

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),
    WithMappings.FromAllInterfaces,
    WithName.Default);

如果你只需要注册那些类,你可以过滤掉那些类,只实现你想要的接口…

public static class EnumerableTypeExtensions
{
    public static IEnumerable<Type> WhichImplementsInterface<T>
        (this IEnumerable<Type> types)
    {
        return types.WhichImplementsInterface(typeof (T));
    }
    public static IEnumerable<Type> WhichImplementsInterface
        (this IEnumerable<Type> types, Type interfaceType)
    {
        return types.WhichImplementsInterface(interfaceType.Name);
    }
    public static IEnumerable<Type> WhichImplementsInterface
        (this IEnumerable<Type> types, string interfaceTypeName)
    {
        return types.Where(t => t.GetInterface(interfaceTypeName) != null);
    }
}

然后你可以像这样使用这些过滤器…

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies().WhichImplementsInterface(typeof(IQueryHandler<,>)),
    WithMappings.FromAllInterfaces,
    WithName.Default);