Хорошо, это может затянуться. Я пытаюсь сделать две вещи:
-
Я хочу иметь класс, который реализует интерфейс, удерживая экземпляр другого класса, к которому направляется каждый вызов.
-
Я также хочу перехватить все вызовы методов и сделать что-то.
Выполнение обоих на своих работах отлично. Сочетание их, кажется, работает только в одном порядке исполнения, и, как это делает Мерфи, он неправильный (по крайней мере для меня).
Я хотел бы сначала добавить композицию, чтобы перехват всех вызовов также перехватил те, которые были предварительно введены.
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();
}
}
}
Я попытался повлиять на порядок выполнения двух аспектов
-
AspectRoleDependency, заставляя перехватчик зависеть от того, чтобы композитор запускался первым
-
AspectPriority, также делая первый запуск композитора.
Поскольку тесты всегда дают
TEST #1
CALL remote implemented
TEST #2
Intercepted before
CALL local implemented
Intercepted after
он явно не работает. У вас есть ключ, почему мой заказ на исполнение не изменился? Я сделал что-то неправильно, я пропустил деталь в документации? Что я могу сделать, чтобы перехватить мои методы, вложенные в композицию?