注册'半封闭'通用组件 [英] Registering 'half-closed' generic component

查看:188
本文介绍了注册'半封闭'通用组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个接口:

  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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆