如何在PostSharp中从另一个方面调用注入方法

本文关键字:一个方面 调用 注入 方法 PostSharp | 更新日期: 2023-09-27 18:01:26

我正在尝试使用PostSharp在学校应用程序上实现观察者模式。

情况如下:我有一个储存库,我想在每次发生更改时通知每个testform(允许在储存库中操作数据的表单)。

这是我想用来添加可观察对象部分到我的存储库的方面:

[Serializable]
class ObservableAspect : InstanceLevelAspect
{
    [IntroduceMember]
    List<TesterForm> LT;
    [IntroduceMember]
    public void notifyChange()
    {
         foreach (TesterForm x in LT)
         {
             x.refreshListBoxBuguri();
         }
    }
    [IntroduceMember]
    public void Subscribe(TesterForm t)
    {
        LT.Add(t);
    }
}

然后这个方面应用于Repository中改变数据的每个方法:

[Serializable]
class ObservableNotify : OnMethodBoundaryAspect
{
    public override void OnExit(MethodExecutionArgs args)
    {
        ((Repository)args.Instance).notifyChange();
    }
}

然后这个方面应用到我的testform构造函数,所以它一创建就订阅我的Repository:

class ObserverAspect : OnMethodBoundaryAspect
{
    public override void OnExit(MethodExecutionArgs args)
    {
        ((TesterForm)args.Instance).controller.repository.Subscribe((TesterForm)args.Instance);
    }
}

现在,我面临的问题是,我不知道如何调用我从一个方面注入的方法,从另一个方面(例如:存储库)。从testform订阅)或者这是否可能。

我在PostSharp网站上做了一些研究,但没有找到这样一个实现的细节。此外,谷歌也没有得出有用的结果。

提前感谢您的帮助!

附加信息:使用VS 2013, PostSharp工作正常,因为我已经建立了其他更简单的方面(日志记录和性能监控),按预期完成工作。

干杯!

如何在PostSharp中从另一个方面调用注入方法

一个方面可以使用[ImportMember]属性访问另一个方面引入的方法。要使其正常工作,导入方面还必须是实例作用域的方面,并且您需要为所有涉及的方面指定正确的执行顺序。

因此,修改后的示例可能看起来像这样:

[AspectTypeDependency( AspectDependencyAction.Order,
                       AspectDependencyPosition.Before,
                       typeof( ObservableNotify ) )]
[Serializable]
class ObservableAspect : InstanceLevelAspect
{
    [IntroduceMember( Visibility = Visibility.Public )]
    public void notifyChange()
    {
        // ...
    }
    // other class members...
}
[Serializable]
class ObservableNotify : OnMethodBoundaryAspect, IInstanceScopedAspect
{
    [ImportMember("notifyChange", IsRequired = true, Order = ImportMemberOrder.AfterIntroductions)]
    public Action notifyChangeMethod;
    public override void OnExit( MethodExecutionArgs args )
    {
        notifyChangeMethod();
    }
    object IInstanceScopedAspect.CreateInstance( AdviceArgs adviceArgs )
    {
        return this.MemberwiseClone();
    }
    void IInstanceScopedAspect.RuntimeInitializeInstance()
    {
    }
}

然而,你也可以采用一种看起来更简洁的解决方案——将所有的编织代码放在单个ObservableAspect中,并用一个简单的ObservableNotify属性标记方法。

[Serializable]
class ObservableAspect : InstanceLevelAspect
{
    private void notifyChange()
    {
        // ...
    }
    // This is the OnExit advice that previously was in a separate aspect.
    [OnMethodExitAdvice]
    [MethodPointcut("SelectMethods")]
    public void OnMethodExit(MethodExecutionArgs args)
    {
        notifyChange();
    }
    // Find all the methods that must be intercepted.
    public IEnumerable<MethodBase> SelectMethods(Type targetType)
    {
        foreach (var methodInfo in targetType.GetMethods())
        {
            if (methodInfo.GetCustomAttributes(typeof (ObservableNotify)).Any())
                yield return methodInfo;
        }
    }
}
class ObservableNotify : Attribute
{
     // This is just a marker attribute used by ObservableAspect.
}