2014-06-20 104 views
12

好的,這可能會變得冗長。我想做兩件事:訂購Postharp方面執行

  • 我想有一個類,實現一個接口,通過持有每個呼叫路由到另一個類的實例。

  • 我也想攔截所有方法調用並做一些事情。

對自己的作品都做得很好。將它們結合起來似乎只能在一個執行順序中工作,而墨菲就是這樣做的,這是錯誤的(至少對我而言)。

我想注入合成第一個,這樣所有調用的攔截也將攔截先前注入的那些。

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 

這顯然是行不通的。你有線索爲什麼我的執行順序沒有改變?我做錯了什麼,我錯過了文檔中的細節嗎?我能做些什麼來攔截我的注入組合物的方法?

+0

您還需要添加'InterceptAspect'的'TestImpl'類來實現你想要的結果。 – nemesv

+0

@nemesv雖然這可能會起作用,但TestImpl類有時並不是我的課程。我更喜歡一種解決方案,我可以將TestImpl保持原樣。 – nvoigt

+0

另外,你可以在'ITest'接口上放置'[InterceptAspect(AttributeInheritance = MulticastInheritance.Multicast)]'。但這是你能得到的最遠的東西。問題是Postsharp在一步之內執行IL,並且它只對編譯時出現的方法應用'InterceptAspect',所以它看不到使用'ComposeAspect'添加的新接口實現。因此,使用'ComposeAspect'添加的類型應該已經包含'InterceptAspect'提供的日誌代碼,並將它放在'ITest'或'TestImpl'類上。 – nemesv

回答

2

隨着當前的方面和你當前的設置,你不能達到你想要的結果。

的問題是如何Postsharp工作:它的IL一步到位揮手,它僅適用的InterceptAspect存在於原始編譯時所以它不會看到與增加了新的接口實現方法ComposeAspect

因此,在這裏沒有排序接受或提供角色,優先級或其他配置。

一種解決方法是對注射TestImpl類中添加InterceptAspect

[InterceptAspect] 
class TestImpl : ITest 
    { 
    public void Call() 
    { 
     Console.WriteLine("CALL remote implemented"); 
    } 
    } 

在這種情況下,記錄邏輯將被直接添加TestImpl所以這些方法將包含日誌記錄時,將組成到您的Test類。

或者如果你沒有標註每一個實現你可以把你的方面接口本身上:

[InterceptAspect(AttributeInheritance = MulticastInheritance.Multicast)] 
interface ITest 
{ 
    void Call(); 
}