2014-06-20 15 views
12

Ok, điều này có thể kéo dài. Tôi đang cố gắng làm hai việc:Sắp xếp các thực thi Các khía cạnh của Postsharp

  • Tôi muốn có một lớp thực hiện giao diện bằng cách giữ một thể hiện của một lớp khác mà mọi cuộc gọi được định tuyến đến.

  • Tôi cũng muốn chặn tất cả các cuộc gọi phương thức và làm điều gì đó.

Làm cả hai đều hoạt động tốt. Kết hợp chúng dường như chỉ hoạt động trong một trật tự thực hiện và khi Murphy có nó, đó là sai lầm (ít nhất là đối với tôi).

Tôi muốn tiêm thành phần trước tiên để chặn tất cả các cuộc gọi cũng sẽ chặn những người đã được tiêm trước đó.

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

tôi đã cố gắng gây ảnh hưởng đến trật tự thực hiện hai khía cạnh của

  • AspectRoleDependency, làm cho đánh chặn phụ thuộc vào nhà soạn nhạc để chạy đầu tiên

  • AspectPriority, cũng làm cho nhà soạn nhạc chạy trước.

Khi kiểm tra luôn mang lại

TEST #1 
CALL remote implemented 

TEST #2 
Intercepted before 
CALL local implemented 
Intercepted after 

nó rõ ràng không hoạt động. Bạn có một đầu mối tại sao lệnh thực hiện của tôi không thay đổi? Tôi đã làm điều gì đó sai, tôi đã bỏ lỡ một chi tiết trong tài liệu? Tôi có thể làm gì để ngăn chặn các phương pháp tiêm thành phần của tôi?

+0

Bạn cũng cần phải thêm 'InterceptAspect' trên lớp 'TestImpl' để đạt được kết quả mong muốn của bạn . – nemesv

+0

@nemesv Mặc dù điều đó có thể làm việc, nhưng lớp TestImpl không phải là lớp của tôi đôi khi.Tôi muốn một giải pháp mà tôi có thể để lại TestImpl như nó được. – nvoigt

+0

Ngoài ra, bạn có thể đặt '[InterceptAspect (AttributeInheritance = MulticastInheritance.Multicast)]' trên chính giao diện 'ITest'. Nhưng đây là điều xa nhất bạn có thể nhận được. Vấn đề là Postsharp làm IL vẫy trong một bước và nó chỉ áp dụng 'InterceptAspect' cho các phương thức có mặt tại thời gian biên dịch để nó không thấy các triển khai giao diện mới được thêm vào với' ComposeAspect'. Vì vậy, kiểu bạn thêm vào với 'ComposeAspect' phải chứa mã đăng nhập được cung cấp bởi' InterceptAspect' với việc đặt nó vào 'ITest' hoặc trên lớp' TestImpl'. – nemesv

Trả lời

2

Với các khía cạnh hiện tại và thiết lập hiện tại của bạn, bạn không thể đạt được kết quả mong muốn.

Vấn đề là trong công việc như thế nào PostSharp: nó IL vẫy trong một bước và nó chỉ áp dụng cho các InterceptAspect các phương pháp mà có mặt tại gốc thời gian biên dịch vì vậy nó không nhìn thấy việc triển khai giao diện mới được bổ sung với ComposeAspect.

Vì vậy, không yêu cầu chấp nhận hoặc cung cấp vai trò, mức độ ưu tiên hoặc cấu hình nào khác sẽ trợ giúp ở đây.

Một workaround sẽ được thêm InterceptAspect trên tiêm TestImpl lớp:

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

Trong trường hợp này logic đăng nhập sẽ được bổ sung trực tiếp TestImpl do đó, những phương pháp sẽ chứa các khai thác gỗ khi nó sẽ được sáng tác vào của bạn Test lớp học.

Hoặc nếu bạn không đánh dấu mỗi thực hiện bạn có thể đặt khía cạnh của bạn trên giao diện chính nó với:

[InterceptAspect(AttributeInheritance = MulticastInheritance.Multicast)] 
interface ITest 
{ 
    void Call(); 
} 
Các vấn đề liên quan