C# 如何为未注册的服务注入null
我有一个装饰器和一个相关服务,如下所示:C# 如何为未注册的服务注入null,c#,dependency-injection,simple-injector,C#,Dependency Injection,Simple Injector,我有一个装饰器和一个相关服务,如下所示: public interface IAdditionalDataService<TResult, TModel> { TResult PopulateAdditionalData(TResult model, params Expression<Func<TModel, object>>[] properties); } public class AdditionalDataDecorato
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;
}
}
// Simple Injector v3.x
container.Register(typeof(IAdditionalDataService<,>),
new[] { typeof(IAdditionalDataService<,>).Assembly });
// Simple Injector v2.x
container.RegisterManyForOpenGeneric(typeof(IAdditionalDataService<,>),
typeof(IAdditionalDataService<,>).Assembly);
公共接口IAdditionalDataService
{
TResult PopulateAdditionalData(TResult模型,
参数表达式[]属性);
}
公共类AdditionalDataDecorator
:IQueryHandler
查询:查询库,IQuery
其中TModel:ModelBase
{
私人只读IQueryHandler(已装饰);
专用只读IAdditionalDataService _additionalDataService;
公共附加数据装饰器(IQueryHandler装饰,
IAdditionalDataService(附加数据服务)
{
_装饰的=装饰的;
_additionalDataService=additionalDataService;
}
公共TResult句柄(TQuery查询)
{
var result=_.Handle(查询);
if(query.RelatedDataProperties!=null&&query.RelatedDataProperties.Any())
结果=_additionalDataService.PopulateAdditionalData(结果,
query.RelatedDataProperties.ToArray());
返回结果;
}
}
装饰程序包装查询处理程序,以便结果由AdditionalDataService
操作,然后返回
问题是并非所有查询结果都需要AdditionalDataService,因此并非每个可能的TResult都有关联的AdditionalDataService实现。如果我尝试在没有对应类型的有效AdditionalDataService实现的情况下使用装饰器,Simple Injector将引发异常
我需要Simple Injector做的事情(仅针对AdditionalDataService)是,如果它没有找到对应类型inject“null”的实现。从那里我可以在调用服务之前测试null
所以我的问题是
当Simple Injector遇到尚未注册的服务请求时,我如何告诉它注入null,而不是抛出异常?您可以创建一个'EmptyAdditionalDataService'
(不执行任何操作)并使用返回未注册的服务
然后,您可以在Handled
方法中检查它是否是EmptyAdditionalDataService
的实例。您可以创建一个'EmptyAdditionalDataService'
(不执行任何操作)并使用为未注册的服务返回它
然后,您可以在Handled
方法中检查它是否是emptyaAdditionalDataService
的实例。您不应该将null
注入应用程序组件的构造函数。这是一种糟糕的做法,因为它使用空检查使代码复杂化。组件应该总是能够假定它得到一个值。因此,构建简单的注入器是为了(几乎)不可能将null
值注入构造函数
相反,您应该使用众所周知的,这就是@manji所指的。但是,与使用ResolveUnregisteredType
事件不同,有一种更简单的方法可以做到这一点
我假设您使用register
注册您的iaditionaldataservice
实现,如下所示:
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;
}
}
// Simple Injector v3.x
container.Register(typeof(IAdditionalDataService<,>),
new[] { typeof(IAdditionalDataService<,>).Assembly });
// Simple Injector v2.x
container.RegisterManyForOpenGeneric(typeof(IAdditionalDataService<,>),
typeof(IAdditionalDataService<,>).Assembly);
//简单注入器v3.x
容器寄存器(类型为(IAdditionalDataService),
新[]{typeof(iaditionaldataservice.Assembly});
//简单喷油器v2.x
container.RegisterManyForOpenGeneric(typeof(IAdditionalDataService),
类型(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<,>));
//简单注入器v3.x
容器注册表条件(
类型(IAdditionalDataService),
类型(EmptyAdditionalDataService),
c=>!c.Handled);
//简单喷油器v2.x
container.RegisterOpenGeneric(
类型(IAdditionalDataService),
类型(EmptyAdditionalDataService));
就是这样。您不应该将null
注入到应用程序组件的构造函数中。这是一种糟糕的做法,因为它使用空检查使代码复杂化。组件应该总是能够假定它得到一个值。因此,构建简单的注入器是为了(几乎)不可能将null
值注入构造函数
相反,您应该使用众所周知的,这就是@manji所指的。但是,与使用ResolveUnregisteredType
事件不同,有一种更简单的方法可以做到这一点
我假设您使用register
注册您的iaditionaldataservice
实现,如下所示:
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;
}
}
// Simple Injector v3.x
container.Register(typeof(IAdditionalDataService<,>),
new[] { typeof(IAdditionalDataService<,>).Assembly });
// Simple Injector v2.x
container.RegisterManyForOpenGeneric(typeof(IAdditionalDataService<,>),
typeof(IAdditionalDataService<,>).Assembly);
//简单注入器v3.x
容器寄存器(类型为(IAdditionalDataService),
新[]{typeof(iaditionaldataservice.Assembly});
//简单喷油器v2.x
container.RegisterManyForOpenGeneric(typeof(IAdditionalDataService),
类型(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<,>));
//简单注入器v3.x
容器注册表条件(
类型(IAdditionalDataService),
类型(EmptyAdditionalDataService),
c=>!c.Handled);
//简单喷油器v2.x
container.RegisterOpenGeneric(
类型(IAdditionalDataService),
类型(EmptyAdditionalDataService));
就是这样。这正是我需要的解决方案,但我无法确定。非常感谢。您是对的,但是使用
RegisterOpenEneric
要简单得多,因为它内置了对此的支持。很抱歉,我最终更改了接受的答案,因为我认为@steven提出了非常有效的观点。这正是我需要的解决方案,但我无法确定。非常感谢。你是对的,但是使用RegisterOpenGeneric要简单得多,因为它内置了对这一点的支持。很抱歉,我最终改变了被接受的答案,因为我认为@steven提出了非常有效的观点。