使用简单的注入器来注册开放泛型

时间:2013-02-21 17:41:40

标签: c# dependency-injection inversion-of-control simple-injector

我有以下课程:

public interface IDbCommandHandler<in TCommand, out TOutput> 
    where TCommand : IDbCommand 
{
    TOutput Handle(TCommand command);
}

public class SubIdentifierItemCreateCommand<TItemType, TDefaultValues> 
    : BaseDbCommand
    where TItemType: TDefaultValues
{

}

public class SubIdentifierItemCreateCommandHandler<TItemType, TDefaultValues>
    : BaseDbCommandHandler<SubIdentifierItemCreateCommand<TItemType, TDefaultValues>, TItemType>,
    IDbCommandHandler<SubIdentifierItemCreateCommand<TItemType, TDefaultValues>, TItemType>
    where TItemType: class, TDefaultValues, IItemForGenericItemByIdentifierRetriever , new()
{

}

我需要将SubIdentifierItemCreateCommandHandler注册为singleton-open-generic,以处理对类型服务的任何请求 IDbCommandHandler<SubIdentifierItemCreateCommand<,>,>

这可能吗?我已经尝试了各种各样的方式,但我总是遇到错误。

_container.RegisterSingleOpenGeneric(
    typeof(IDbCommandHandler<,>),
    typeof(SubIdentifierItemCreateCommandHandler<,>));

_container.RegisterOpenGeneric(
    typeof(IDbCommandHandler<,>),
    typeof(SubIdentifierItemCreateCommandHandler<,>));

// this one is throws a compile-time error, that you cannot 
// use partial open types.
_container.RegisterManyForOpenGeneric(
    typeof(IDbCommandHandler<SubIdentifierItemCreateCommand<,>,>),
    typeof(SubIdentifierItemCreateCommandHandler<,>)); 

我希望能够打电话给下面的工作:

var item = _container.GetInstance<
    IDbCommandHandler<
        SubIdentifierItemCreateCommand<
            SectionData, 
            ISectionDataDefaultValues>, 
        SectionData>>();

1 个答案:

答案 0 :(得分:0)

不幸的是,你偶然发现了框架中的一个错误。 Simple Injector 1.6.1无法正确处理“where TItemType:TDefaultValues”约束。

解决方案很简单,迁移到Simple Injector 2.0via NuGet)。

如果您因任何原因无法切换到Simple Injector 2.0,您可以注册ResolveUnregisteredType事件以注册该类型以解决1.6.1版本中的错误:

container.ResolveUnregisteredType += (sender, e) =>
{
    var serviceType = e.UnregisteredServiceType;

    if (serviceType.IsGenericType &&
        serviceType.GetGenericTypeDefinition() == typeof(IDbCommandHandler<,>))
    {
        var commandArg = serviceType.GetGenericArguments()[0];
        var outputArg = serviceType.GetGenericArguments()[1];

        if (commandArg.IsGenericType &&
            commandArg.GetGenericTypeDefinition() == 
                typeof(SubIdentifierItemCreateCommand<,>))
        {
            var itemTypeArgument = commandArg.GetGenericArguments()[0];
            var defaultValuesArgument = commandArg.GetGenericArguments()[1];

            if (itemTypeArgument != outputArg)
            {
                return;
            }

            Type typeToRegister;

            try
            {
                typeToRegister =
                    typeof(SubIdentifierItemCreateCommandHandler<,>)
                    .MakeGenericType(itemTypeArgument.GetGenericArguments());
            }
            catch (ArgumentException)
            {
                // Thrown by MakeGenericType when the type constraints 
                // do not match. In this case, we don't have to register
                // anything and can bail out.
                return;
            }

            object singleInstance = container.GetInstance(typeToRegister);

            // Register the instance as singleton.
            e.Register(() => singleInstance);
        }
    }
};

我知道,这很难看,但至少有一个解决方法; - )