注册'半封闭'通用组件 [英] Registering 'half-closed' generic component
问题描述
我有两个接口:
public interface IQuery< TResult> {}
public interface IQueryHandler< in TQuery,out TResult>
其中TQuery:IQuery< TResult>
{
TResult Handle(TQuery q);
}
一个关闭IQueryHandler实现的例子:
public class EventBookingsHandler:IQueryHandler< EventBookings,IEnumerable< EventBooking>>
{
private readonly DbContext _context;
public EventBookingsHandler(DbContext context)
{
_context = context;
}
public IEnumerable< EventBooking> Handle(EventBookings q)
{
return _context.Set< MemberEvent>()
.OfEvent(q.EventId)
.AsEnumerable()
.Select(EventBooking .FromMemberEvent);
$ / code>
我可以注册和解析<$
Classes.FromAssemblyContaining(typeof> c $ c $> IQueryHandler<,>
(IQueryHandler<,>))
.BasedOn(typeof(IQueryHandler<,>))
.WithServiceAllInterfaces()
然而,我想要做的是解决一个半关闭的开放式泛型实现(即指定一个通用的 TQuery
类型参数):
public class GetById< TEntity> :IQuery< TEntity>其中TEntity:class,IIdentity
{
public int Id {get;私人设置; }
public GetById(int id)
{
Id = id;
}
}
public class GetByIdHandler< TEntity> :IQueryHandler< GetById< TEntity>,TEntity>其中TEntity:class,IIdentity
{
private readonly DbContext _context;
public GetByIdHandler(DbContext context)
{
_context = context;
public TEntity Handle(GetById< TEntity> q)
{
return _context.Set< TEntity>()。Find(q.Id);
当我试图解析 IqueryHandler< GetById< Event> Event>
我得到了这个异常:
MicroKernel.Handlers.GenericHandlerTypeMismatchException'发生在Castle.Windsor.dll中,但未在用户代码中处理。
其他信息:类型Queries.GetById'1 [[Models.Event, Domain,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]],Models.Event不满足组件'Queries.GetByIdHandler'1'的实现类型Queries.GetByIdHandler'1的通用约束。这很可能是你的代码中的一个bug。
它看起来类型已经成功注册,并且约束满足我可以告诉( Event
是一个类并实现 IIdentity
)。我在这里错过了什么?我试图做一些温莎无法应对的事情吗?
尽管Castle中的这段代码失败:
public void Resolve_GetByIdHandler_Succeeds()
{
var container = new Castle.Windsor.WindsorContainer();
$ b container.Register(Component
.For(typeof(IQueryHandler<,>))
.ImplementedBy(typeof(GetByIdHandler<>)));
var x = container.Resolve< IQueryHandler< GetById< Event> ;, Event>>();
Simple Injector 的工作原理:
public void GetInstance_GetByIdHandler_Succeeds()
{
var container = new SimpleInjector.Container();
container.RegisterOpenGeneric(
typeof(IQueryHandler<,>),
typeof(GetByIdHandler<>));
var x = container.GetInstance< IQueryHandler< GetById< Event> ;, Event>>();
}
I have two interfaces:
public interface IQuery<TResult> { }
public interface IQueryHandler<in TQuery, out TResult>
where TQuery : IQuery<TResult>
{
TResult Handle(TQuery q);
}
An example of a closed implementation of IQueryHandler:
public class EventBookingsHandler : IQueryHandler<EventBookings, IEnumerable<EventBooking>>
{
private readonly DbContext _context;
public EventBookingsHandler(DbContext context)
{
_context = context;
}
public IEnumerable<EventBooking> Handle(EventBookings q)
{
return _context.Set<MemberEvent>()
.OfEvent(q.EventId)
.AsEnumerable()
.Select(EventBooking.FromMemberEvent);
}
}
I can register and resolve closed generic implementations of IQueryHandler<,>
with this component registration:
Classes.FromAssemblyContaining(typeof(IQueryHandler<,>))
.BasedOn(typeof(IQueryHandler<,>))
.WithServiceAllInterfaces()
However what I would like to do is resolve an open generic implementation that is "half closed" (ie specifies a generic TQuery
type parameter):
public class GetById<TEntity> : IQuery<TEntity> where TEntity : class, IIdentity
{
public int Id { get; private set; }
public GetById(int id)
{
Id = id;
}
}
public class GetByIdHandler<TEntity> : IQueryHandler<GetById<TEntity>, TEntity> where TEntity : class, IIdentity
{
private readonly DbContext _context;
public GetByIdHandler(DbContext context)
{
_context = context;
}
public TEntity Handle(GetById<TEntity> q)
{
return _context.Set<TEntity>().Find(q.Id);
}
}
When I tried to resolve IQueryHandler<GetById<Event>, Event>
I got this exception:
An exception of type 'Castle.MicroKernel.Handlers.GenericHandlerTypeMismatchException' occurred in Castle.Windsor.dll but was not handled in user code
Additional information: Types Queries.GetById'1[[Models.Event, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Models.Event don't satisfy generic constraints of implementation type Queries.GetByIdHandler'1 of component 'Queries.GetByIdHandler'1'. This is most likely a bug in your code.
It looks like the type has successfully registered, and the constraints are satisfied as far as I can tell (Event
is a class and implements IIdentity
). What am I missing here? Am I trying to do something that Windsor can't cope with?
(I'm not posting this up as an answer, just as some useful information that is too much info for a comment.)
While this code in Castle fails:
public void Resolve_GetByIdHandler_Succeeds()
{
var container = new Castle.Windsor.WindsorContainer();
container.Register(Component
.For(typeof(IQueryHandler<,>))
.ImplementedBy(typeof(GetByIdHandler<>)));
var x = container.Resolve<IQueryHandler<GetById<Event>, Event>>();
}
The same thing in Simple Injector works:
public void GetInstance_GetByIdHandler_Succeeds()
{
var container = new SimpleInjector.Container();
container.RegisterOpenGeneric(
typeof(IQueryHandler<,>),
typeof(GetByIdHandler<>));
var x = container.GetInstance<IQueryHandler<GetById<Event>, Event>>();
}
这篇关于注册'半封闭'通用组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!