我正在尝试使用PostSharp在学校应用程序上实现Observer模式。
情况如下: 我有一个存储库,我希望每次更改时都通知每个TesterForm(允许在存储库中操作数据的表单)。
这是我想用来将Observable部分添加到我的存储库的方面:
[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();
}
}
然后将此方面应用于我的TesterForm构造函数,以便它在创建后立即订阅我的存储库:
class ObserverAspect : OnMethodBoundaryAspect
{
public override void OnExit(MethodExecutionArgs args)
{
((TesterForm)args.Instance).controller.repository.Subscribe((TesterForm)args.Instance);
}
}
现在,我面临的问题是我不知道如何从另一个方面(例如:来自TesterForm的repository.Subscribe)调用我注入一个方面的方法,或者这是否可能。
我在PostSharp网站上做了一些研究,但没有找到关于这种实现的细节。此外,谷歌没有产生任何有用的结果。
提前感谢您的帮助!
附加信息:使用VS 2013,PostSharp可以正常工作,因为我已经构建了其他更简单的方面(日志记录和性能监控),可以按预期完成工作。
干杯!
答案 0 :(得分:2)
方面可以使用[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.
}