2011-08-23 4 views
8

내 응용 프로그램에서는 이전에 메서드에 "주석을 추가"하기 위해 일반 C# 특성을 사용했습니다. 예컨대 :한 가지 방법의 여러 측면

 

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

 

무엇 SpecialAttributeLogicHere()했던, 반 성적이 특정 방법을 주석 모든 푸 - 속성을보고했다. 그런 다음 (자체적으로) 모든 키와 값에 대해 고유 한 사전을 만듭니다.

이제 OnAntry 내에서 SpecialAttributeLogic을 (더 깨끗한 메서드 본문에서 제거하여) aspect에 넣을 수 있기 때문에 PostSharp로 이동하려고합니다. Foo는 OnMethodBoundaryAspect를 확장하는 애스펙트로 대체 될 것입니다.


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

를하지만 푸가 OnEntry을 가지고있는 경우 "SpecialAttributeLogic는"두 번 실행된다는 것을 의미한다 :

나는 아직도 그것을 다음과 같은 방법을 사용하고 싶습니다. 기본적으로 각 Foo()의 모든 키와 값을 사전에 "모으고"사전에 논리를 적용해야합니다.

PostSharp로이를 수행하는 방법 (또는 모범 사례)은 무엇입니까? 감사!

+0

실례를 아래의 답에서 추가했습니다. –

답변

2

메서드 내부에 이름 가치 쌍을 구축하려는 것 같습니다. 어떤면에서는 이것을 할 수 없습니다. 제가 제안하는 것은 MethodInterceptionAspect를 사용하여 메서드의 특성을 반영한 다음 컬렉션을 작성하고 매개 변수를 통해 (아마도 오버로드 된 메서드를 사용하여) 메서드에 전달하거나 클래스 멤버로 설정하는 것입니다.

성능을 최적화하기 위해 컴파일 타임에 값을 반영 할 수 있습니다.

다음은 문제를 신속하게 해결하는 방법입니다. 약간 추한 것입니다 (맞추기 위해 수정할 필요가 있습니다). 다른 방법이 있지만 "일반적인"것이 아닙니다.

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

대상 및 값은 모두 런타임시 소비를 위해 컴파일 타임 (런타임 아님)으로 초기화됩니다. 그들은 컴파일 타임에 aspect로 직렬화된다. 이렇게하면 런타임에 반사 충돌을 줄일 수 있습니다.

+0

좋은 답변입니다. 또는 동일한 접근 방식을 사용할 수 있지만 MethodInterceptionAspect 대신 OnMethodBoundaryAspect를 사용한다고 가정합니다. 그런 다음 OnEntry에서 리플렉션을 사용하여 메서드의 특성을 읽습니다. 그러나 다른 한편으로는 아마도 MethodInterceptionAspect가 내 요구에 더 좋습니다. 나는 그것에게 약간의 생각을 주어야 할 것이다. –

+1

네, 그렇게 할 수는 있지만, 문제가 속성에서 그것을 colelcted했다면 데이터에 접근하고 있습니다. 당신이 여러 측면을 실행하고 코드를 복잡하게 만드는 결과를 가져 오기 때문에 속성을 측면으로 만들지는 않을 것입니다. 그러나 MethodBoundaryAspect를 사용하면 메서드 오버로드가 필요하지 않습니다. 따라서 어느 쪽이라도 괜찮을 것입니다. –

0

메모와 마찬가지로, 결국 MethodInterceptionAspect를 사용하고 OnInvoke 만 재정의했습니다. OnInvoke 내에서 args.Method.GetCustomAttributes()를 보았습니다. 설정 한 모든 System.Attributes (DustinDavis의 예제에서 SpecialAttribute)를 제공합니다.

이러한 속성과 속성을 사용하여 실행할 논리를 실행할 수 있습니다. 논리가 성공하면 args.Proceed()로 끝내고 그렇지 않으면 예외가 발생합니다.

관련 문제