代码之家  ›  专栏  ›  技术社区  ›  Olaf

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

  •  1
  • Olaf  · 技术社区  · 10 年前

    这篇博客文章描述了一个很好的存储库模式替代方案。

    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);
        }
    }
    

    作者使用依赖注入容器SimpleInjector一次注册所有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);
    
    1 回复  |  直到 10 年前
        1
  •  2
  •   TylerOhlsen    10 年前

    如果您要实现 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);