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提出了非常有效的观点。