2015-07-06 4 views
1

Я пытаюсь реализовать шаблон Observer в школьном приложении, используя PostSharp.Как вызвать введенный метод из другого аспекта в PostSharp

ситуация выглядит следующим образом: У меня есть Repository, что я хочу, чтобы уведомить каждый TesterForm (формы, которые позволяют манипулировать данные в хранилище) каждый раз, когда производится изменение.

Это аспект, который я хочу использовать, чтобы добавить Observable часть моей 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); 
    } 
} 

Тогда этот аспект применительно к каждому методу в хранилище, которое изменяет данные:

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

} 

Теперь проблема, с которой я сталкиваюсь, заключается в том, что я понятия не имею, как вызвать метод, который я вставляю с одним аспектом, из другого аспекта (например: репозиторий.Subscribe from TesterForm) или это даже возможно.

Я провел некоторое исследование на веб-сайте PostSharp, но не нашел никаких подробностей о такой реализации. Кроме того, Google не принес никаких полезных результатов.

Заранее благодарим за помощь!

Дополнительная информация: используя VS 2013, PostSharp работает правильно, поскольку я создал другие более простые аспекты (протоколирование и мониторинг производительности), которые выполняют свою работу по назначению.

Cheers!

ответ

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. 
} 
Смежные вопросы