mardi 23 mai 2017

Invoking generic extension method with parameters

Consider the following extension method:

public static class ValiDoc
{
        public static IEnumerable<RuleDescription> GetRules<T>(this AbstractValidator<T> validator, bool documentNested = false)
        {
             //....
        }
}

An implementation of AbstractValidator:

public class AddressValidator : AbstractValidator<Address>
{
    public AddressValidator()
    {
        RuleFor(address => address.HouseNumber).NotEmpty();
        RuleFor(address => address.StreetName).NotEmpty();
        RuleFor(address => address.PostCode).NotEmpty();
    }
}

I want to invoke the GetRules() extension method on ValiDoc via reflection and pass in an instance of AddressValidator as the first parameter, with a boolean for the second.

Having never played with Reflection before I am pretty overwhelmed, however by following the examples available here I have made some progress.

//Parameter 1
Type type = typeof(AbstractValidator<>);

// Instance of Address
Type constructed = type.MakeGenericType(childValidator.ValidatorType.GetTypeInfo().BaseType.GenericTypeArguments[0]);

// Find the extension method based on the signature I have defined for the usage
// public static IEnumerable<RuleDescription> GetRules<T>(this AbstractValidator<T> validator, bool documentNested = false)
var runtimeMethods = typeof(ValiDoc).GetRuntimeMethods();

MethodInfo generatedGetRules = null;

// Nothing fancy for now, just pick the first option as we know it is GetRules
using (IEnumerator<MethodInfo> enumer = runtimeMethods.GetEnumerator())
{
    if (enumer.MoveNext()) generatedGetRules = enumer.Current;
}

// Create the generic method instance of GetRules()
generatedGetRules = generatedGetRules.MakeGenericMethod(constructed);

//Parameter 1 = Derived from AbstractValidator<T>, Parameter 2 = boolean
var parameterArray = new object[] { childValidator.GetValidator(new PropertyValidatorContext(new ValidationContext(rule.Member.DeclaringType), rule, propertyName)), true };

//Invoke extension method with validator instance
generatedGetRules.Invoke(null, parameterArray);

When executing generatedGetRules.Invoke, I receive the following error message:

'Object of type 'ValiDoc.Tests.TestData.Validators.AddressValidator' cannot be converted to type 'FluentValidation.AbstractValidator1[FluentValidation.AbstractValidator1[ValiDoc.Tests.TestData.POCOs.Address]]'.'

Have I missed anything obvious? I can't tell if I am nearly there or miles away.

Supporting values:

typeof(AbstractValidator<>) = {FluentValidation.AbstractValidator`1[T]}

childValidator.ValidatorType.GetTypeInfo().BaseType.GenericTypeArguments[0] = {ValiDoc.Tests.TestData.POCOs.Address}

constructed = {FluentValidation.AbstractValidator`1[ValiDoc.Tests.TestData.POCOs.Address]}

generatedGetRules = {System.Collections.Generic.IEnumerable1[ValiDoc.Output.RuleDescription] GetRules[AbstractValidator1](FluentValidation.AbstractValidator1[FluentValidation.AbstractValidator1[ValiDoc.Tests.TestData.POCOs.Address]], Boolean)}

Parameter array = {ValiDoc.Tests.TestData.Validators.AddressValidator}, boolean





Aucun commentaire:

Enregistrer un commentaire