如何从属性方面调用具有属性名称和前缀的特定方法?

时间:2018-08-16 13:09:41

标签: c# aop postsharp

我想用possharp开发一个NotifyDataErrorInfoAspect。

值的验证取决于几个可变属性(MinValue,MaxValue ...)。合同不能使用可变参数。

我想构建类似于DependencyPropertyAspect的东西。 具有[DependencyProperty]的每个属性都有许多可选方法。例如ValidatePropertyName。

[DependencyProperty]
public string Email { get; set; }

private bool ValidateEmail(string value)
{
    return EmailRegex.IsMatch(value);
}

我该怎么做?

[NotifyDataErrorInfo]
public string Name{ get; set; }
private IList<DataErrorInfo> ValidateName(string value)
{
    return this.IsValidName(value);
}

[NotifyDataErrorInfo]
public int Age{ get; set; }
private IList<DataErrorInfo> ValidateAge(int value)
{
    return this.IsValidAge(value);
}

[NotifyDataErrorInfo]
public string Email { get; set; }
private IList<DataErrorInfo> ValidateEmail(string value)
{
    return this.IsValidEmail(value);
}

属性ImportMethod()仅允许使用固定的方法名称。 最好的方法是什么?

1 个答案:

答案 0 :(得分:1)

当需要导入没有固定预定义名称的方法时,可以在方面实现IAdviceProvider接口,并提供将方法名称作为字符串参数的ImportMethodAdviceInstance。 / p>

另一个重要的一点是,您的Validate方法采用特定类型的参数,而不是object。当前,无法在C#中创建一般属性,因此您需要创建两个方面类来处理这种情况:作为方面提供者的属性和一般方面的实现。

以下是NotifyDataErrorInfo方面的示例实现:

[PSerializable]
public class NotifyDataErrorInfoAttribute : LocationLevelAspect, IAspectProvider
{
    public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
    {
        Type propertyType = ((LocationInfo)targetElement).LocationType;
        Type aspectType = typeof(NotifyDataErrorInfoAspectImpl<>).MakeGenericType(propertyType);

        yield return new AspectInstance(
            targetElement, (IAspect) Activator.CreateInstance(aspectType));
    }
}

[PSerializable]
public class NotifyDataErrorInfoAspectImpl<T> : ILocationInterceptionAspect,
                                                IInstanceScopedAspect,
                                                IAdviceProvider
{
    public Func<T, IList<DataErrorInfo>> ValidateDelegate;

    public IEnumerable<AdviceInstance> ProvideAdvices(object targetElement)
    {
        LocationInfo property = (LocationInfo)targetElement;
        string validateMethodName = "Validate" + property.Name;

        yield return new ImportMethodAdviceInstance(
            typeof(NotifyDataErrorInfoAspectImpl<>).GetField("ValidateDelegate"),
            validateMethodName,
            true);
    }

    public void OnSetValue(LocationInterceptionArgs args)
    {
        if (ValidateDelegate((T) args.Value)?.Any() == true)
            throw new ArgumentException("...");

        args.ProceedSetValue();
    }

    public void OnGetValue(LocationInterceptionArgs args)
    {
        args.ProceedGetValue();
    }

    public void RuntimeInitialize(LocationInfo locationInfo)
    {
    }

    public object CreateInstance(AdviceArgs adviceArgs)
    {
        return this.MemberwiseClone();
    }

    public void RuntimeInitializeInstance()
    {
    }
}