2011-08-23 40 views
8

Trong ứng dụng của tôi, trước đây tôi đã sử dụng các thuộc tính C# thông thường để "chú thích" một phương thức. Ví dụ:Nhiều khía cạnh trên một phương thức

 

[Foo(SomeKey="A", SomeValue="3")] 
[Foo(SomeKey="B", SomeValue="4")] 
public void TheMethod() 
{ 
    SpecialAttributeLogicHere(); 
} 

 

Điều gì SpecialAttributeLogicHere() làm là xem xét phản ánh tất cả thuộc tính Foo đã chú thích phương pháp cụ thể này. Sau đó, nó sẽ tự mình tạo một từ điển riêng cho tất cả các khóa và giá trị.

Tôi hiện đang cố gắng chuyển sang PostSharp, vì SpecialAttributeLogic có thể được đưa vào một khía cạnh (và được xóa khỏi thân phương thức sạch hơn nhiều!), Trong OnEntry. Foo sẽ được thay thế bằng một khía cạnh mở rộng OnMethodBoundaryAspect.

tôi vẫn muốn sử dụng nó theo cách sau:


[Foo(SomeKey="A", SomeValue="3")] 
[Foo(SomeKey="B", SomeValue="4")] 

Nhưng nếu Foo có OnEntry, mà có nghĩa là "SpecialAttributeLogic" sẽ được thực hiện hai lần. Tôi về cơ bản cần phải "thu thập" tất cả các khóa và giá trị từ mỗi Foo(), thành một từ điển, mà sau đó tôi áp dụng một số logic để.

Làm cách nào để thực hiện điều này (hoặc các phương pháp hay nhất) với PostSharp? Cảm ơn!

+0

thêm ví dụ làm việc vào câu trả lời của tôi bên dưới. –

Trả lời

2

Dường như bạn muốn xây dựng một thanh ghi đè bên trong phương thức của mình. Bạn không thể làm điều này với một khía cạnh. Những gì tôi đề nghị là bạn sử dụng một MethodInterceptionAspect và phản ánh các thuộc tính trên phương thức sau đó xây dựng bộ sưu tập của bạn và truyền nó trong phương thức thông qua một tham số (có thể sử dụng một phương thức quá tải) hoặc thiết lập nó như là một thành viên của lớp.

Bạn có thể phản ánh giá trị tại thời gian biên dịch để giữ hiệu suất tối ưu.

Đây là giải pháp nhanh chóng cho vấn đề của bạn. Đó là một chút xấu xí (bạn sẽ cần phải thực hiện sửa đổi để phù hợp). Có nhiều cách khác nhưng chúng không phải là "chung chung".

namespace ConsoleApplication12 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyExampleClass ec = new MyExampleClass(); 
      ec.MyMethod(); 
     } 
    } 

    public class MyExampleClass 
    { 
     [Special(Key = "test1", Value = "1234")] 
     [Special(Key = "test2", Value = "4567")] 
     [MyAspect] 
     public void MyMethod() 
     { 
      MyMethod(new Dictionary<string, string>()); 
     } 

     public void MyMethod(Dictionary<string, string> values) 
     { 
      //Do work 
     } 

    } 

    [Serializable] 
    public class MyAspect : MethodInterceptionAspect 
    { 
     Dictionary<string, string> values = new Dictionary<string, string>(); 
     MethodInfo target; 

     public override void CompileTimeInitialize(System.Reflection.MethodBase method, AspectInfo aspectInfo) 
     { 
      target = method.DeclaringType.GetMethod(method.Name, new Type[] { typeof(Dictionary<string, string>) }); 

      foreach (Attribute a in method.GetCustomAttributes(false)) 
      { 
       if (a is SpecialAttribute) 
       { 
        values.Add(((SpecialAttribute)a).Key, ((SpecialAttribute)a).Value); 
       } 
      } 
     } 

     public override void OnInvoke(MethodInterceptionArgs args) 
     { 
      if (values == null || values.Count < 1) 
      { 
       args.Proceed(); 
      } 
      else 
      { 
       target.Invoke(args.Instance, new object[] { values }); 
      } 

     } 
    } 
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true) ] 
    public class SpecialAttribute : Attribute 
    { 
     public string Key { get; set; } 
     public string Value { get; set; } 
    } 
} 

mục tiêu và giá trị đều được khởi tạo ở chế độ kết hợp (không phải thời gian chạy) để tiêu thụ khi chạy. Họ nhận được hàng loạt với các khía cạnh tại compiletime. Bằng cách này bạn tiết kiệm được sự phản chiếu khi chạy.

+0

Câu trả lời hay. Ngoài ra, tôi cho rằng tôi có thể làm cùng một cách tiếp cận, nhưng sử dụng OnMethodBoundaryAspect thay vì MethodInterceptionAspect. Sau đó, trong OnEntry tôi sẽ đọc các thuộc tính cho phương thức sử dụng sự phản chiếu. Nhưng mặt khác, có lẽ MethodInterceptionAspect là tốt hơn cho nhu cầu của tôi. Tôi sẽ phải cho nó một số suy nghĩ ... –

+1

Có, bạn có thể làm điều đó, nhưng vấn đề là nhận được quyền truy cập vào dữ liệu khi bạn đã colelcted nó từ các thuộc tính. Tôi sẽ không làm cho các thuộc tính một khía cạnh bởi vì bạn sẽ kết thúc có nhiều khía cạnh thực hiện và thực sự phức tạp mã của bạn. Nhưng việc sử dụng MethodBoundaryAspect ngăn cản sự quá tải của phương thức. Vì vậy, một trong hai cách nên được ok. –

0

Cũng giống như một lưu ý, tôi đã kết thúc bằng cách sử dụng MethodInterceptionAspect và chỉ ghi đè OnInvoke. Trong OnInvoke, tôi đã xem args.Method.GetCustomAttributes(), cho tôi tất cả System.Attributes mà tôi đã đặt (ví dụ: SpecialAttribute in DustinDavis 'example).

Sử dụng các thuộc tính đó và thuộc tính của chúng, tôi có thể chạy logic mà tôi cần để chạy. Nếu logic thành công, tôi kết thúc với args.Proceed(), nếu tôi không ném một ngoại lệ.

Các vấn đề liên quan