I'm a GitHub rookie but I'll try creating a pull request this week to incorporate this into the existing ChildCollectionValidatorAdaptor and extensions... but for now this seems to do the trick (based from ChildCollectionValidatorAdaptor):
publicclass ParentChildCollectionValidatorAdaptor<T,TCollectionElement> : NoopPropertyValidator {privatereadonly Func<T, IValidator<TCollectionElement>> validatorFactory;public Func<object, bool> Predicate { get; set; }public ParentChildCollectionValidatorAdaptor(Func<T, IValidator<TCollectionElement>> validatorFactory) {this.validatorFactory = validatorFactory; }publicoverride IEnumerable<ValidationFailure> Validate(PropertyValidatorContext context) {if (context.Rule.Member == null) {thrownew InvalidOperationException(string.Format("Nested validators can only be used with Member Expressions.")); }var parent = (T)context.ParentContext.InstanceToValidate;var validator = validatorFactory.Invoke(parent);var collection = context.PropertyValue as IEnumerable;if (collection == null) {yieldbreak; }int count = 0;var predicate = Predicate ?? (x => true);foreach (var element in collection) {if (element == null || !(predicate(element))) { count++;continue; }var newContext = new ValidationContext(element, context.ParentContext.PropertyChain, context.ParentContext.Selector); newContext.PropertyChain.Add(context.Rule.Member); newContext.PropertyChain.AddIndexer(count++);var results = validator.Validate(newContext).Errors;foreach (var result in results) {yieldreturn result; } } } }publicstaticclass ParentChildCollectionValidatorAdaptorExtensions {publicstatic CollectionValidatorExtensions.ICollectionValidatorRuleBuilder<T, TCollectionElement> SetCollectionValidator<T, TCollectionElement>(this IRuleBuilder<T, IEnumerable<TCollectionElement>> ruleBuilder, Func<T, IValidator<TCollectionElement>> validatorFactory) {var adaptor = new ParentChildCollectionValidatorAdaptor<T, TCollectionElement>(validatorFactory); ruleBuilder.SetValidator(adaptor);returnnew CollectionValidatorRuleBuilder<T, TCollectionElement>(ruleBuilder, adaptor); }privateclass CollectionValidatorRuleBuilder<T,TCollectionElement> : CollectionValidatorExtensions.ICollectionValidatorRuleBuilder<T, TCollectionElement> {privatereadonly IRuleBuilder<T, IEnumerable<TCollectionElement>> ruleBuilder;privatereadonly ParentChildCollectionValidatorAdaptor<T, TCollectionElement> adaptor;public CollectionValidatorRuleBuilder(IRuleBuilder<T, IEnumerable<TCollectionElement>> ruleBuilder, ParentChildCollectionValidatorAdaptor<T, TCollectionElement> adaptor) {this.ruleBuilder = ruleBuilder;this.adaptor = adaptor; }public IRuleBuilderOptions<T, IEnumerable<TCollectionElement>> SetValidator(IPropertyValidator validator) {return ruleBuilder.SetValidator(validator); }public IRuleBuilderOptions<T, IEnumerable<TCollectionElement>> SetValidator(IValidator validator) {return ruleBuilder.SetValidator(validator); }public IRuleBuilderOptions<T, IEnumerable<TCollectionElement>> SetValidator(IValidator<IEnumerable<TCollectionElement>> validator) {return ruleBuilder.SetValidator(validator); }public IRuleBuilderOptions<T, IEnumerable<TCollectionElement>> Configure(Action<PropertyRule> configurator) {return ((IRuleBuilderOptions<T, IEnumerable<TCollectionElement>>)ruleBuilder).Configure(configurator); }public CollectionValidatorExtensions.ICollectionValidatorRuleBuilder<T, TCollectionElement> Where(Func<TCollectionElement, bool> predicate) {if (predicate == null) thrownew ArgumentNullException("predicate","Cannot pass null to Where"); adaptor.Predicate = x => predicate((TCollectionElement)x);returnthis; } } }
Usage:
publicclass WorkDayValidator : AbstractValidator<WorkDay> {public WorkDayValidator() { RuleFor(workDay => workDay.Date).NotNull(); RuleFor(workDay => workDay.WorkItems).SetCollectionValidator(workDay => new WorkItemValidator(workDay)); } }
Cheers,
mike