How to call an entered method from another aspect in PostSharp

I am trying to implement an Observer pattern in a school application using PostSharp.

The situation is this: I have a repository that I want to notify every TesterForm (forms that allow you to manipulate data in the repository) with every change.

This is the aspect that I want to use to add the observable part to my repository:

[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); } } 

This aspect is then applied to all methods in the repository that modify data:

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

And then this aspect is applied to my TesterForm constructor, so it subscribes to my repository right after it is created:

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

Now the problem I am facing is that I have no idea how to call the method that I am inserting with one aspect from another aspect (for example: .Subscribe from TesterForm repository) or is it even possible.

I did some research on the PostSharp website, but did not find any details about such an implementation. In addition, Google did not bring any useful results.

Thanks in advance for your help!

Additional information: using VS 2013, PostSharp works correctly, since I created other simpler aspects (logging and performance monitoring) that do their job as intended.

Hooray!

+1
source share
1 answer

An aspect can access the methods introduced by another aspect using the [ImportMember] attribute. In order for this to work correctly, the import aspect must also be an instance-specific aspect, and you would like to indicate the correct execution order for all aspects involved.

So your modified example might look like this:

 [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() { } } 

However, you can also go with a solution that looks a bit cleaner - have all the weaving code in a single ObservableAspect and tag the methods with a simple ObservableNotify attribute.

 [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. } 
+2
source

Source: https://habr.com/ru/post/1268451/


All Articles