Unity 3.5:通过其开放的通用接口检索具体实现
Unity 3.5: Retrieve concrete implementation by its open generic interface
此博客 post 描述了存储库模式的一个很好的替代方案。
https://cuttingedge.it/blogs/steven/pivot/entry.php?id=92
作者建议使用命令和查询而不是存储库。特定博客 post 描述了 .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);
如果您要有许多 IQueryHandler<,>
的特定实现而不是一个通用版本,那么您不能使用开放通用来注册。但是您可以使用反射来查找所有实现并分别注册它们。 (这就是 RegisterTypes 在幕后为您所做的)。
您已接近尝试调用问题中的 RegisterTypes,但您使用了 WithMappings.FromMatchingInterface
。这将只注册 classes 及其接口,这些接口符合 MyClass : IMyClass
的命名约定(在 class 名称前加上 'I'
)。如果您改为使用 WithMappings.FromAllInterfaces
注册,您将获得所需的注册。
container.RegisterTypes(
AllClasses.FromLoadedAssemblies(),
WithMappings.FromAllInterfaces,
WithName.Default);
如果您只需要注册那些 classes,您可以将 classes 过滤为仅那些实现了您想要的接口的...
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);
此博客 post 描述了存储库模式的一个很好的替代方案。
https://cuttingedge.it/blogs/steven/pivot/entry.php?id=92
作者建议使用命令和查询而不是存储库。特定博客 post 描述了 .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);
如果您要有许多 IQueryHandler<,>
的特定实现而不是一个通用版本,那么您不能使用开放通用来注册。但是您可以使用反射来查找所有实现并分别注册它们。 (这就是 RegisterTypes 在幕后为您所做的)。
您已接近尝试调用问题中的 RegisterTypes,但您使用了 WithMappings.FromMatchingInterface
。这将只注册 classes 及其接口,这些接口符合 MyClass : IMyClass
的命名约定(在 class 名称前加上 'I'
)。如果您改为使用 WithMappings.FromAllInterfaces
注册,您将获得所需的注册。
container.RegisterTypes(
AllClasses.FromLoadedAssemblies(),
WithMappings.FromAllInterfaces,
WithName.Default);
如果您只需要注册那些 classes,您可以将 classes 过滤为仅那些实现了您想要的接口的...
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);