OK, może to zająć dużo czasu. Staram się zrobić dwie rzeczy:Zamawianie realizacji Postsharp Aspects
Chcę mieć klasy, która implementuje interfejs trzymając wystąpienie innej klasy, że każde połączenie jest kierowane do.
Chcę również przechwycić wszystkie wywołania metod i zrobić coś.
Wykonanie obu na podstawie własnych dzieł świetnie. Łączenie ich wydaje się działać tylko w jednym rozkazie wykonania i jak ma go Murphy, to jest złe (przynajmniej dla mnie).
Chciałbym wstrzyknąć kompozycję najpierw, aby przechwycenie wszystkich połączeń również przechwyciło te, które zostały wcześniej wstrzyknięte.
namespace ConsoleApplication13
{
using System;
using System.Reflection;
using PostSharp;
using PostSharp.Aspects;
using PostSharp.Aspects.Dependencies;
using PostSharp.Extensibility;
[Serializable]
[ProvideAspectRole("COMPOSER")]
public sealed class ComposeAspectAttribute : CompositionAspect
{
[NonSerialized]
private readonly Type interfaceType;
private readonly Type implementationType;
public ComposeAspectAttribute(Type interfaceType, Type implementationType)
{
this.interfaceType = interfaceType;
this.implementationType = implementationType;
}
// Invoked at build time. We return the interface we want to implement.
protected override Type[] GetPublicInterfaces(Type targetType)
{
return new[] { this.interfaceType };
}
// Invoked at run time.
public override object CreateImplementationObject(AdviceArgs args)
{
return Activator.CreateInstance(this.implementationType);
}
}
[Serializable]
[ProvideAspectRole("INTERCEPTOR")]
[MulticastAttributeUsage(MulticastTargets.Method)]
[AspectRoleDependency(AspectDependencyAction.Order, AspectDependencyPosition.After, "COMPOSER")]
public sealed class InterceptAspectAttribute : MethodInterceptionAspect
{
public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
{
base.CompileTimeInitialize(method, aspectInfo);
// Warning in VS output
Message.Write(method, SeverityType.Warning, "XXX", "Method: " + method.Name);
}
public override void OnInvoke(MethodInterceptionArgs args)
{
Console.WriteLine("Intercepted before");
args.Proceed();
Console.WriteLine("Intercepted after");
}
}
interface ITest
{
void Call();
}
class TestImpl : ITest
{
public void Call()
{
Console.WriteLine("CALL remote implemented");
}
}
[InterceptAspect(AspectPriority = 1)]
[ComposeAspect(typeof(ITest), typeof(TestImpl), AspectPriority = 2)]
class Test
{
// this should, after compilation, have all methods of ITest, implemented through an instance of TestImpl, which get intercepted before TestImpl is called
public void CallLocalImplementedTest()
{
Console.WriteLine("CALL local implemented");
}
}
class Program
{
static void Main()
{
var test = new Test();
ITest t = Post.Cast<Test, ITest>(test);
Console.WriteLine("TEST #1");
t.Call();
Console.WriteLine("TEST #2");
test.CallLocalImplementedTest();
Console.ReadLine();
}
}
}
Próbowałem wpłynąć na kolejność wykonywania dwóch aspektach przez
AspectRoleDependency, dzięki czemu przechwytywania zależy od kompozytora do uruchomienia pierwszego
AspectPriority, również przy kompozytora być pierwszym na mecie.
W testach zawsze dają
TEST #1
CALL remote implemented
TEST #2
Intercepted before
CALL local implemented
Intercepted after
to oczywiście nie działa. Czy masz pojęcie, dlaczego moja kolejność wykonania się nie zmieniła? Czy zrobiłem coś złego, czy brakowało mi szczegółów w dokumentacji? Co mogę zrobić, aby przechwycić również moje metody iniekcji składu?
Trzeba także dodać 'InterceptAspect' w klasie' TestImpl' aby osiągnąć pożądany rezultat . – nemesv
@nemesv Chociaż to by prawdopodobnie działało, czasami klasa TestImpl nie jest moją klasą.Wolałbym rozwiązanie, w którym mogę pozostawić TestImpl tak, jak jest. – nvoigt
Alternatywnie możesz umieścić '[InterceptAspect (AttributeInheritance = MulticastInheritance.Multicast)]' na samym interfejsie 'ITest'. Ale to jest najdalsze, co możesz dostać. Problem polega na tym, że Postsharp wykonuje falowanie IL w jednym kroku i stosuje tylko "InterceptAspect" do metod obecnych w czasie kompilacji, więc nie widzi nowych implementacji interfejsu dodanych za pomocą "ComposeAspect". Tak więc typ dodawany do 'ComposeAspect' powinien już zawierać kod rejestrowania dostarczony przez' InterceptAspect' z umieszczeniem go w klasie 'ITest' lub' TestImpl'. – nemesv