Quantcast
Channel: Fluent Validation for .NET
Viewing all articles
Browse latest Browse all 1917

New Post: Handling inheritance

$
0
0
I needed something similiar for one-to-one properties that could be of several subclass types so I adapted your PolymorphicCollectionValidator to a PolymorphicValidator and it seems to be working great.

An example of the situation I needed this for is:

A "BillingInfo" object has a "PaymentInfo" property.
The PaymentInfo property may contain an instance of "CreditCardPaymentInfo" or "DirectDebitPaymentInfo", both of which derive from "PaymentInfo".

Here's the class I adapted to meet these needs:
 public class PolymorphicValidator<TBaseClass> : NoopPropertyValidator
    {
        Dictionary<Type, IValidator> derivedValidators = new Dictionary<Type, IValidator>();
        IValidator<TBaseClass> baseValidator;

        public PolymorphicValidator(IValidator<TBaseClass> baseValidator)
        {
            this.baseValidator = baseValidator;
        }

        public PolymorphicValidator<TBaseClass> Add<TDerived>(IValidator<TDerived> derivedValidator) where TDerived : TBaseClass
        {
            derivedValidators[typeof(TDerived)] = derivedValidator;
            return this;
        }

        public override IEnumerable<ValidationFailure> Validate(PropertyValidatorContext context)
        {
            var objToValidate = context.PropertyValue;

            // bail out if the property is null 
            if (objToValidate == null) return Enumerable.Empty<ValidationFailure>();
            
            // get the first element out of the collection and check its real type. 
            var actualType = objToValidate.GetType();

            IValidator derivedValidator;
            ChildValidatorAdaptor childValidator;

            if (derivedValidators.TryGetValue(actualType, out derivedValidator))
            {
                // we found a validator for the specific subclass. 
                childValidator = new ChildValidatorAdaptor(derivedValidator);
                return childValidator.Validate(context);
            }

            // Otherwise fall back to the validator for the base class.
            childValidator = new ChildValidatorAdaptor(baseValidator);
            return childValidator.Validate(context);
        }
    }
The validators for PaymentInfo, CreditCardPaymentInfo and DirectDebitPaymentInfo were all created just like the "Person, Employee, Member" example above.

Then in the BillingInfoValidator, I set the PaymentInfo property's validator to the new PolymorphicValidator like so: (Yes, I could have done it more "fluently", but for readability sake, I went one line at a time to show how each validator is registered.)
            var paymentInfoValidator = new PolymorphicValidator<PaymentInfo>(new PaymentInfoBaseValidator<PaymentInfo>());
            paymentInfoValidator.Add<CreditCardPaymentInfo>(new CreditCardPaymentInfoValidator());
            paymentInfoValidator.Add<DirectDebitPaymentInfo>(new DirectDebitPaymentInfoValidator());
            RuleFor(e => e.PaymentInfo).SetValidator(paymentInfoValidator);

Viewing all articles
Browse latest Browse all 1917

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>