2014-02-17 2 views
-1

특성이있는 특성이 있습니다 (다시 Func<object, object>). 특성 변경시 해당 특성이 실행되도록 (업데이트 된 특성 값을 in T으로 사용)합니다. 그렇게하는 가장 슬픈 방법은 무엇입니까?속성 변경시 속성에 유지 된 Execute 함수

참고 : 나는 정적을하고 자신의 양수인이/invocaction 변경에 따라 실행되도록 설계되지 않았습니다 속성 사실을 알고 있어요. 난 그저 내가 만든 프로토 타입에 최대한 가깝게 작업 할 필요가있다.

일부 코드 :

using System; 
using System.Windows; 

namespace AnnotatedBinding 
{ 
    public class AnnotatedPropertyAttribute: Attribute 
    { 
     // static 
     public AnnotatedPropertyAttribute(Func<object, object> evaluator) 
     { 
      Evaluator = evaluator; 
     } 

     public Func<object, object> Evaluator 
     { 
      get; private set; 
     } 
    } 

    public class Test 
    { 
     [AnnotatedProperty(Test.TestEvaluator)] // not compiling!, guess it's fixable by passing in a member info and then calling Reflection Invoke? 
     public string TestProperty 
     { 
      get; set; 
     } 

     public static Func<object, object> TestEvaluator = (x) => MessageBox.Show(x.ToString()); 
    } 

    public class Shell 
    { 
     public void Run() 
     { 
      var test = new Test(); 

      test.TestProperty = "blah";// I want my message box here 

      test.TestProperty = "blah";// and I don't want it here 
     } 
    } 
} 

답변

2

TestProperty에 귀하의 속성은 컴파일되지 않습니다

그래서 당신이해야 할 모든이 같은 뭔가 재산의 설정 기능을 변경하는 것입니다 대리자는 특성 인수로 허용되지 않기 때문입니다. 허용되는 유형에 대한 자세한 내용은 this answer from Eric Lippert을 참조하십시오.

리플렉션을 사용하여 해결 방법에 대해 : System.Typestring이 유효한 속성 인수 유형이므로 메서드를 소유 한 형식과 특성에서 메서드 이름을 확실히 지정할 수 있습니다. 다음과 같은 내용이 있습니다.

[AnnotatedProperty(typeof(Test), "TestEvaluator")] 
public string TestProperty { get; set; } 

그러나 속성을 설정하면 위임자와 아무 관계가 없습니다. 속성은 리플렉션을 사용하여 런타임 중에 (특히 MemberInfo.GetCustomAttributes(...)을 사용하여) 읽을 수 있고 속성 값을 기반으로 모든 작업을 수행하고 분석 할 수있는 메타 데이터입니다. 이 모든 작업은 수동으로 수행해야합니다. 안타깝게도 .NET Framework는 멤버에 적용된 특성을 기반으로 일부 작업을 자동으로 수행하는 기능을 제공하지 않습니다. 이렇게하면 부동산 변경 통지가 훨씬 쉬워집니다.

따라서 속성을 수동으로 처리해야합니다. 즉, getset 접근자를 구현하고 속성이 해당 속성에 적용되는지 여부를 확인하고 실행해야하는 대리자를 결정한 다음 리플렉션을 사용하여 실행합니다. 물론, setter에서 메소드에 대한 호출을 대신 추가하기 때문에 이치에 맞지 않습니다.

TL; DR :

가능한 해결 방법 : 당신은 PostSharp 봐, .NET에서 aspect 지향 프로그래밍을 지원하는 라이브러리가 있어야합니다. 컴파일 후 보일러 플레이트 코드를 메소드 나 다른 멤버에 주입하는 데 사용할 수 있습니다. MSIL 코드를 분석하고 소위 "aspect"(실제로는 여러분의 것과 같은 속성)를 검색하여이를 수행합니다. 발견되면 속성에 지정된대로 MSIL을 수정합니다. PostSharp 기본 속성/애스펙트에서 속성을 추출한 다음 적절한 메소드를 대체해야합니다.귀하의 경우에는 LocationInterceptionAspect에서 파생 된 후 OnSetValue(...) 메서드를 재정의해야합니다. 이 방법에서는 위의 속성 인수를 사용하여 대리인을 결정한 다음 리플렉션을 사용하여이를 호출합니다. "Intercepting Properties and Fields" in the PostSharp documentation이 방법에 대해 아주 잘 설명합니다.

난 당신이 같은 끝낼 것이라고 생각 : 나는 오류의 대부분을 생략

public class Test 
{ 
    public static void TestMethod(string someMessage) 
    { 
     MessageBox.Show(someMessage); 
    } 

    [ExecuteDelegateOnPropertySetAspect(typeof(Test), "TestMethod", new object[] { "Hello world!" })] 
    public string TestProperty { get; set; } 
} 

참고 :

public class ExecuteDelegateOnPropertySetAspect : LocationInterceptionAspect 
{ 
    public ExecuteDelegateOnPropertySetAspect(Type methodOwner, string methodName, object[] arguments) 
    { 
     this.MethodOwner = methodOwner; 
     this.MethodName = methodName; 
     this.Arguments = arguments; 
    } 

    public Type MethodOwner { get; set; } 
    public string MethodName { get; set; } 
    public object[] Arguments { get; set; } 

    public override void OnSetValue(LocationInterceptionArgs args) 
    { 
     // get method with the specified name from the specified owner type 
     MethodInfo method = this.MethodOwner.GetMethod(this.MethodName); 

     // method must be static, otherwise we would need an instance to call it 
     if (method != null && method.IsStatic) 
     { 
      if (method.GetParameters().Length == this.Arguments.Length) 
      { 
       // call the method with the given arguments 
       method.Invoke(null, this.Arguments); 
      } 
     } 

     // execute the original setter code 
     args.ProceedSetValue(); 
    } 
} 

그리고 코드에서이 부분을 당신의 재산에 적용 할

그것을 간단하고 짧게 유지하기위한 널 검사.

+0

러빙 http://www.postsharp.net/ – user1514042

0

당신이 보인다는 C#에서 속성의 개념을 오해한다.
속성에는 getter 및 setter 기능이 있습니다. 속성을 설정하거나 값을 얻을 때 자동으로 실행됩니다. 그런 다음 전화

public class Test 
{ 
    private string _testProperty; 
    private bool testPropertyIsSet = false; 

    public string TestProperty 
    { 
     get { return this._testProperty; } 
     set 
     { 
      _testProperty = value; 
      if (!testPropertyIsSet) 
      { 
       // Do something here when your property gets set for the first time 
      } 
      testPropertyIsSet = true; 
     } 
    } 
} 

을 :

public void Run() 
{ 
    var test = new Test(); 

    test.TestProperty = "blah"; 
    test.TestProperty = "blah2"; 
} 
+0

LOL. 당신은 내 질문을 이해하는 것처럼 보였습니다. 요즘 Stacky가 어떻게 작동합니까? 다만 그것이 충분히 명확하지 않은 경우를 대비해서 - 나는 외부 평가자를 어떤 이유로 든 전달할 수 있기를 원합니다. – user1514042

+0

@ user1514042 : 속성을 설정할 때 속성의 함수가 어떻게 든 실행되는 것 같아 보이는 질문을 읽는 중 ... –

+0

@Paolo Tedesco 알아요 :) – user1514042

관련 문제