注册有条件的开放泛型
Registering open generics with condition
是否可以在不指定实现类型的情况下使用 RegisterConditional
(类似于 Register
的工作方式,但有条件)?
我正在使用 Simple Injector 为我的 CQRS/MVC 应用程序连接流畅的验证。到目前为止,注册验证器(由 MVC 和 CQRS 堆栈装饰器管道使用)一直很简单:
container.Register(typeof(IValidator<>), assemblies, lifestyle);
container.RegisterConditional(
typeof(IValidator<>),
typeof(ValidateNothingDecorator<>),
Lifestyle.Singleton,
c => !c.Handled)
一项新要求意味着我需要实施类似于验证器的功能,但会提供警告。由于各种原因,我不想使用 Fluent Validation 的内置 "error level",这意味着我需要为给定类型创建额外的验证器,这当然会为单个类型验证错误提供多个注册。
我想做的是注册任何实现 IValidator<>
的东西,除非它也实现 IProvideWarnings
,但我不想列出每个 class 来注册
public class MyCommand : IDefineCommand {...}
public class ValidateMyCommand : IValidator<MyCommand> {...}
public class ProvideWarningsForMyCommand : IValidator<MyCommand>, IProvideWarnings {...}
...
// would like something like... (this obviously does not work)
container.RegisterConditional(
typeof(IValidator<>),
assemblies,
lifestyle,
c => !c.ImplementationType.GetInterfaces().Contains(typeof(IProvideWarnings)));
我的备用位置是找到所有实现 IValidator<>
但不实现 IProvideWarnings
的类型并将其传递给 Register
,但是,我宁愿在注册中使用谓词来完成调用而不是不同的查找。
谢谢
我解决这个问题的方法是使用我的备用位置。
记住下面的代码中有一个非标准的方法(但应该足够直接),它看起来像:
var validatorTypes = assemblies.SelectMany(a => a.GetTypes().Where(t =>
t.IsClass && !t.IsAbstract && t.IsPublic &&
t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IValidator<>)) &&
!t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IProvideWarnings<>))
)).ToList();
IocContainer.Register(typeof(IValidator<>), validatorTypes, IocContainer.DefaultLifestyle);
IocContainer.RegisterConditional(typeof(IValidator<>), typeof(ValidateNothingDecorator<>), Lifestyle.Singleton, c => !c.Handled && !c.ServiceType.DoesImplement(typeof(IProvideWarnings)));
正如您已经注意到的,Simple Injector 包含 Register
的重载,允许提供要注册的类型列表。虽然您可以自己反思程序集,但 Simple Injector 包含一个方便的 GetTypesToRegister
方法来为您完成这项工作。 GetTypesToRegister
会自动为您过滤掉装饰器和泛型类型定义。
以下注册就可以了:
var validatorTypes =
container.GetTypesToRegister(typeof(IValidator<>))
.Where(typeof(IProvideWarnings).IsAssignableFrom);
container.Register(typeof(IValidator<>), validatorTypes, lifestyle);
是否可以在不指定实现类型的情况下使用 RegisterConditional
(类似于 Register
的工作方式,但有条件)?
我正在使用 Simple Injector 为我的 CQRS/MVC 应用程序连接流畅的验证。到目前为止,注册验证器(由 MVC 和 CQRS 堆栈装饰器管道使用)一直很简单:
container.Register(typeof(IValidator<>), assemblies, lifestyle);
container.RegisterConditional(
typeof(IValidator<>),
typeof(ValidateNothingDecorator<>),
Lifestyle.Singleton,
c => !c.Handled)
一项新要求意味着我需要实施类似于验证器的功能,但会提供警告。由于各种原因,我不想使用 Fluent Validation 的内置 "error level",这意味着我需要为给定类型创建额外的验证器,这当然会为单个类型验证错误提供多个注册。
我想做的是注册任何实现 IValidator<>
的东西,除非它也实现 IProvideWarnings
,但我不想列出每个 class 来注册
public class MyCommand : IDefineCommand {...}
public class ValidateMyCommand : IValidator<MyCommand> {...}
public class ProvideWarningsForMyCommand : IValidator<MyCommand>, IProvideWarnings {...}
...
// would like something like... (this obviously does not work)
container.RegisterConditional(
typeof(IValidator<>),
assemblies,
lifestyle,
c => !c.ImplementationType.GetInterfaces().Contains(typeof(IProvideWarnings)));
我的备用位置是找到所有实现 IValidator<>
但不实现 IProvideWarnings
的类型并将其传递给 Register
,但是,我宁愿在注册中使用谓词来完成调用而不是不同的查找。
谢谢
我解决这个问题的方法是使用我的备用位置。
记住下面的代码中有一个非标准的方法(但应该足够直接),它看起来像:
var validatorTypes = assemblies.SelectMany(a => a.GetTypes().Where(t =>
t.IsClass && !t.IsAbstract && t.IsPublic &&
t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IValidator<>)) &&
!t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IProvideWarnings<>))
)).ToList();
IocContainer.Register(typeof(IValidator<>), validatorTypes, IocContainer.DefaultLifestyle);
IocContainer.RegisterConditional(typeof(IValidator<>), typeof(ValidateNothingDecorator<>), Lifestyle.Singleton, c => !c.Handled && !c.ServiceType.DoesImplement(typeof(IProvideWarnings)));
正如您已经注意到的,Simple Injector 包含 Register
的重载,允许提供要注册的类型列表。虽然您可以自己反思程序集,但 Simple Injector 包含一个方便的 GetTypesToRegister
方法来为您完成这项工作。 GetTypesToRegister
会自动为您过滤掉装饰器和泛型类型定义。
以下注册就可以了:
var validatorTypes =
container.GetTypesToRegister(typeof(IValidator<>))
.Where(typeof(IProvideWarnings).IsAssignableFrom);
container.Register(typeof(IValidator<>), validatorTypes, lifestyle);