如何为未注册的服务注入 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<,>));
就是这样。
我有一个装饰器和一个如下所示的关联服务:
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<,>));
就是这样。