如何为未注册的服务注入 null

How to inject null for unregistered services

我有一个装饰器和一个如下所示的关联服务:

public interface IAdditionalDataService<TResult, TModel>
{
    TResult PopulateAdditionalData(TResult model, 
        params Expression<Func<TModel, object>>[] properties);
}

public class AdditionalDataDecorator<TQuery, TResult, TModel> 
    : IQueryHandler<TQuery, TResult>
    where TQuery : QueryBase<TResult, TModel>, IQuery<TResult>
    where TModel : ModelBase
{
    private readonly IQueryHandler<TQuery, TResult> _decorated;
    private readonly IAdditionalDataService<TResult, TModel> _additionalDataService;

    public AdditionalDataDecorator(IQueryHandler<TQuery, TResult> decorated,
        IAdditionalDataService<TResult, TModel>  additionalDataService)
    {
        _decorated = decorated;
        _additionalDataService = additionalDataService;
    }

    public TResult Handle(TQuery query)
    {
        var result = _decorated.Handle(query);

        if (query.RelatedDataProperties != null && query.RelatedDataProperties.Any())
            result = _additionalDataService.PopulateAdditionalData(result,
                query.RelatedDataProperties.ToArray());

        return result;
    }
}

装饰器包装查询处理程序,以便结果由 AdditionalDataService 操作然后返回。

问题不是我的所有查询结果都需要 AdditionalDataService,因此并非每个可能的 TResult 都有关联的 AdditionalDataService 实现。如果我尝试在没有相应类型的有效 AdditionalDataService 实现的情况下使用装饰器,则简单注入器会抛出异常。

我需要 Simple Injector 做的 - 仅针对 AdditionalDataService - 如果它没有找到相应类型注入的实现 "null"。从那里我可以在调用服务之前测试 null。

所以我的问题是

如何让 Simple Injector 在遇到未注册的服务请求时注入 null,而不是抛出异常?

您可以使用 Container.ResolveUnregisteredType Event.[=14= 创建一个 'EmptyAdditionalDataService'(什么都不做)和 return 它用于未注册的服务]

然后您可以在 Handled 方法中检查它是否是 EmptyAdditionalDataService 的实例。

您应该永远不要null注入您的应用程序组件的构造函数中。这是一种不好的做法,因为它会使带有空值检查的代码变得复杂。一个组件应该总是能够假定它获得了一个值。因此,Simple Injector 的构建使其(几乎)不可能将 null 值注入构造函数。

相反,您应该使用众所周知的 Null Object pattern,这就是 @manji 所指的。但是,除了使用 ResolveUnregisteredType 事件,还有一种更简单的方法可以做到这一点。

我假设您使用 Register 注册您的 IAdditionalDataService<TResult, TModel> 实现,就像这样:

// Simple Injector v3.x
container.Register(typeof(IAdditionalDataService<,>),
    new[] { typeof(IAdditionalDataService<,>).Assembly });

// Simple Injector v2.x
container.RegisterManyForOpenGeneric(typeof(IAdditionalDataService<,>),
    typeof(IAdditionalDataService<,>).Assembly);

后备注册现在可以注册如下:

// Simple Injector v3.x
container.RegisterConditional(
    typeof(IAdditionalDataService<,>),
    typeof(EmptyAdditionalDataService<,>),
    c => !c.Handled);

// Simple Injector v2.x
container.RegisterOpenGeneric(
    typeof(IAdditionalDataService<,>),
    typeof(EmptyAdditionalDataService<,>));

就是这样。