使用参数调用通用扩展方法
Invoking generic extension method with parameters
考虑以下扩展方法:
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 时,我收到以下错误消息:
'Object of type 'ValiDoc.Tests.TestData.Validators.AddressValidator'
cannot be converted to type
'FluentValidation.AbstractValidator1[FluentValidation.AbstractValidator
1[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[AbstractValidator
1](FluentValidation.AbstractValidator1[FluentValidation.AbstractValidator
1[ValiDoc.Tests.TestData.POCOs.Address], 布尔值)}
参数数组={ValiDoc.Tests.TestData.Validators.AddressValidator},boolean
编辑:
工作实施:
// 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>;
在您的错误消息中,我看到 AddressValidator
(AbstractValidator<Address>
) 无法转换为 AbstractValidator<AbstractValidator<Address>>
,这正是您正在做的。 Constructed 是 而不是 你想传递给 MakeGenericMethod 的东西,我假设,因为该方法在 T 上是通用的,但第一个参数是 this AbstractValidator<T>
所以你得到一个双通用专业化而不是你想要的。
考虑以下扩展方法:
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 时,我收到以下错误消息:
'Object of type 'ValiDoc.Tests.TestData.Validators.AddressValidator' cannot be converted to type 'FluentValidation.AbstractValidator
1[FluentValidation.AbstractValidator
1[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[AbstractValidator
1](FluentValidation.AbstractValidator1[FluentValidation.AbstractValidator
1[ValiDoc.Tests.TestData.POCOs.Address], 布尔值)}
参数数组={ValiDoc.Tests.TestData.Validators.AddressValidator},boolean
编辑: 工作实施:
// 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>;
在您的错误消息中,我看到 AddressValidator
(AbstractValidator<Address>
) 无法转换为 AbstractValidator<AbstractValidator<Address>>
,这正是您正在做的。 Constructed 是 而不是 你想传递给 MakeGenericMethod 的东西,我假设,因为该方法在 T 上是通用的,但第一个参数是 this AbstractValidator<T>
所以你得到一个双通用专业化而不是你想要的。