【问题标题】:How call a specific method from property aspect with property name and prefix?如何使用属性名称和前缀从属性方面调用特定方法?
【发布时间】:2018-08-17 20:25:24
【问题描述】:

我想用 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() 只允许固定的方法名。 最好的方法是什么?

【问题讨论】:

    标签: c# aop postsharp


    【解决方案1】:

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

    另一个重要的一点是,您的 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()
        {
        }
    }
    

    【讨论】:

    • 很好的答案!我会将其放入我的项目中并进行测试。一些问题。 INotifyDataErrorInfo 的实现我有另一个方面类。我使用 NotifyPropertyChangeAspect。这两个方面应该如何协同工作?我不想在我的类中复制 NotifyPropertyChangeAspect,但也不必指定第二个方面。我不知道 NotifyPropertyChangeAspect 的代码。你有没有一些我需要注意的地方。
    • 我想分析验证代码以查找与其他属性的依赖关系。应考虑相关验证。 “最大值”更改应该调用值的验证。
    • 1) NotifyDataErrorInfoAttribute.ProvideAspects 方法还可以在定义属性的类型上提供 NotifyPropertyChangedAttribute。您可以使用IAspectRepositoryService 来检查该方面是否已应用于该类型。但是,我认为在这种情况下,分别指定这两个方面会更清晰,因为每个方面都在您的代码中提供不同的行为。您还想在 INPC (doc.postsharp.net/aspect-dependencies) 之前订购您的方面。
    • 2) 您可以使用 PostSharp 的 ReflectionSearch 类中的 GetMethodsUsingDeclaration 方法。因此,在您的示例中,您会找到使用 get_MaxValue 的所有 set_Property 方法。然后您可以导入这些属性的验证方法并在运行时调用它们。
    猜你喜欢
    • 1970-01-01
    • 2014-05-30
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    • 2012-10-24
    • 2011-05-13
    相关资源
    最近更新 更多