【问题标题】:Invoking generic extension method with parameters使用参数调用泛型扩展方法
【发布时间】:2017-05-23 20:59:25
【问题描述】:

考虑以下扩展方法:

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

AbstractValidator 的实现:

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

我想通过反射调用 ValiDoc 上的 GetRules() 扩展方法,并传入一个 AddressValidator 实例作为第一个参数,第二个参数是布尔值。

在不知所措之前从未玩过 Reflection,但是通过遵循此处提供的示例,我取得了一些的进步。

//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);

执行 generatedGetRules.Invoke 时,我收到以下错误消息:

''ValiDoc.Tests.TestData.Validators.AddressValidator' 类型的对象 无法转换为类型 'FluentValidation.AbstractValidator1[FluentValidation.AbstractValidator1[ValiDoc.Tests.TestData.POCOs.Address]]'。'

我错过了什么明显的东西吗?我不知道我是在附近还是在几英里之外。

支持值:

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

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

构造 = {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)}

参数数组 = {ValiDoc.Tests.TestData.Validators.AddressValidator},布尔值

编辑: 工作实施:

// 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(childValidator.ValidatorType.GetTypeInfo().BaseType.GenericTypeArguments[0]);

                //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
                var output = generatedGetRules.Invoke(null, parameterArray) as IEnumerable<RuleDescription>;

【问题讨论】:

    标签: c# generics reflection .net-core .net-standard


    【解决方案1】:

    在您的错误消息中,我看到 AddressValidator (AbstractValidator&lt;Address&gt;) 无法转换为 AbstractValidator&lt;AbstractValidator&lt;Address&gt;&gt;,这正是您正在做的。我假设构造是不是您想要传递给 MakeGenericMethod 的,因为该方法在 T 上是通用的,但第一个参数是 this AbstractValidator&lt;T&gt;,因此您将获得双重通用专业化而不是你想要什么。

    【讨论】:

    • 成功了 - 问题已更新为答案。非常感谢您的帮助:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多