Sco*_*nen 2 .net c# dependency-injection
我正在使用 Microsoft.Extensions.DependencyInjection 中的 IServiceCollection/IServiceProvider。
我想将一个委托注入一个类:
public delegate ValidationResult ValidateAddressFunction(Address address);
public class OrderSubmitHandler
{
private readonly ValidateAddressFunction _validateAddress;
public OrderSubmitHandler(ValidateAddressFunction validateAddress)
{
_validateAddress = validateAddress;
}
public void SubmitOrder(Order order)
{
var addressValidation = _validateAddress(order.ShippingAddress);
if(!addressValidation.IsValid)
throw new Exception("Your address is invalid!");
}
}
Run Code Online (Sandbox Code Playgroud)
ValidateAddressFunction我要注入的实现来自一个必须从容器解析的类,因为它有自己的依赖项:
public class OrderValidator
{
private readonly ISomeDependency _dependency;
public OrderValidator(ISomeDependency dependency)
{
_dependency = dependency;
}
public ValidationResult ValidateAddress(Address address)
{
// use _dependency
// validate the order
// return a result
return new ValidationResult();
}
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我使用了一个委托,但我也可以注入Func<Address, ValidationResult>.
我可以只注入OrderValidator,但我不想只用一种方法创建一个接口。如果我的班级需要的只是一种方法,那么我宁愿直接依赖它。
我如何注册委托或Func以这样的方式在解析时,包含该方法的类将被解析,然后我可以使用解析实例中的方法?
注册委托或Func<Address, ValidationResult>使用解析提供方法的类型的工厂方法,然后返回该方法。
在您的示例中,您希望解析OrderValidator并返回其ValidateAddress方法。
// register the class that provides the method and its dependencies.
services.AddSingleton<OrderValidator>();
services.AddSingleton<ISomeDependency, SomeDependency>();
// register the delegate using a factory method that resolves
// the type that provides the method and then returns the method.
services.AddSingleton<ValidateAddressFunction>(serviceProvider =>
{
var validator = serviceProvider.GetRequiredService<OrderValidator>();
return validator.ValidateAddress;
});
Run Code Online (Sandbox Code Playgroud)
如果您注册Func<Address, ValidationResult>而不是委托,这将完全相同:
services.AddSingleton<Func<Address,ValidationResult>>(serviceProvider =>
{
var validator = serviceProvider.GetRequiredService<OrderValidator>();
return validator.ValidateAddress;
});
Run Code Online (Sandbox Code Playgroud)
您可以使用扩展程序简化注册。它并没有那么短,但如果您可能有多个这样的注册,它仍然有帮助。它也可能有助于表达您的意图,因此很明显您正在注册要注入的委托,而不是类实例或接口实现:
public static class ServiceCollectionDelegateExtensions
{
public static IServiceCollection RegisterDelegateFromService<TService, TDelegate>(
this IServiceCollection serviceCollection,
Func<TService, TDelegate> getDelegateFromService)
where TDelegate : Delegate
{
return serviceCollection.AddTransient(serviceProvider =>
getDelegateFromService(serviceProvider.GetRequiredService<TService>()));
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,委托是注册使用的,AddTransient因为类的生命周期实际上是在注册类时确定的。
现在注册看起来像这样:
services.RegisterDelegateFromService<OrderValidator, ValidateAddressFunction>
(validator => validator.ValidateAddress);
Run Code Online (Sandbox Code Playgroud)