2010-01-13 2 views
4

표현 나무에 관해서는 초보자입니다. 그래서이 질문이나 사용할 용어를 묻는 방법을 모르겠습니다. 여기에 내가 할 노력하고있어의 지나치게 simplifed 버전입니다 :표현 트리 - 인스턴스를 선언하는 방법은 무엇입니까?

Bar bar = new Bar(); 
Zap(() => bar.Foo); 

public static void Zap<T>(Expression<Func<T>> source) 
{ 
    // HELP HERE: 
    // I want to get the bar instance and call bar.Zim() or some other method. 
} 

어떻게이 기력 방법 내부에 바받을 수 있나요?

+1

'Zap (() => 1)'이라고하면 어떻게 될까요? –

+1

그럼 bar.Zim()을 호출하지 않겠습니다. :-) 진심으로, 내가 건네받은 것이 Bar 인스턴스인지보고 싶으면, 인스턴스 메소드를 호출하십시오. 가능한? –

답변

6

Zap 메서드에 전달 된 표현식이 트리이므로 Expression Tree Visitor을 사용하여 트리를 걸어 식에서 첫 번째 ConstantExpression을 찾아야합니다. 그것은 아마 다음과 같은 순서에있을 것입니다 다음 bar 인스턴스가 2 MemberExpression 어디에서 오는지이다 일원으로 인스턴스 내부 클래스로 구현되는 폐쇄에 의해 포착되어

(((source.Body as MemberExpression).Expression as MemberExpression).Expression as ConstantExpression).Value 

참고.

편집

는 그런 다음과 같이 생성 된 폐쇄에서 필드를 얻을 수 있습니다

static void Main(string[] args) 
    { 
     var bar = new Bar(); 
     bar.Foo = "Hello, Zap"; 
     Zap(() => bar.Foo); 
    } 

    private class Bar 
    { 
     public String Foo { get; set; }  
    } 

    public static void Zap<T>(Expression<Func<T>> source) 
    { 
     var param = (((source.Body as MemberExpression).Expression as MemberExpression).Expression as ConstantExpression).Value; 
     var type = param.GetType(); 
     // Note that the C# compiler creates the field of the closure class 
     // with the name of local variable that was captured in Main() 
     var field = type.GetField("bar"); 
     var bar = field.GetValue(param) as Bar; 
     Debug.Assert(bar != null); 
     Console.WriteLine(bar.Foo); 
    } 
+0

감사합니다. 나는 그것을 시도 할 것이다. –

+0

나는 그것을 시도했다. 닫기 : 위의 표현식은 컴파일러에서 생성 한 내부 클래스를 제공합니다. 그 클래스에 저장된 bar 인스턴스에 접근해야합니다. 나는 놀았고 그것을 알아낼 수 없었다. 내가 뭘 놓치고 있니? –

+0

좋아, 대답을 업데이트했다. – codekaizen

5

는 "바"의 종류를 알고 있다면, 당신은 난 (이 작업을 수행 할 수 있습니다 여기서 codekaizen의 답변에서 일부 비트 재사용) :

static void Main(string[] args) 
    { 
     var bar = new Bar(); 
     bar.Foo = "Hello, Zap"; 
     Zap(() => bar.Foo); 

     Console.ReadLine(); 
    } 

    private class Bar 
    { 
     public String Foo { get; set; } 
    } 

    public static void Zap<T>(Expression<Func<T>> source) 
    { 
     var body = source.Body as MemberExpression; 
     Bar test = Expression.Lambda<Func<Bar>>(body.Expression).Compile()(); 
     Console.WriteLine(test.Foo); 
    } 

대부분의 경우 표현식 tre 내에서 객체를 나타내는 표현식을 찾을 수 있습니다 e를 생성 한 다음이 표현식을 컴파일하고 실행하여 객체를 가져옵니다 (그러나 이것은 매우 빠른 작업이 아닙니다). 그래서 누락 된 부분은 Compile() 메소드입니다. 여기서 좀 더 자세한 정보를 찾을 수 있습니다 : How to: Execute Expression Trees.

이 코드에서는 항상 "() => object.Member"와 같은 표현식을 전달한다고 가정합니다. 실제 시나리오의 경우 필요한식이 있는지 분석해야합니다 (예 : MemberExpression이 아닌 경우 예외를 throw). 또는 일종의 까다로운 ExpressionVisitor를 사용하십시오.

내가 최근에 여기에 매우 비슷한 질문 대답했다 : 거인의 어깨에 How do I subscribe to an event of an object inside an expression tree?

1

상임를 위, 다음과 같이 식의 소스가 보이는 나타내는 클래스의 인스턴스를 추출하는 내 마지막 확장 방법 :

public static TIn GetSource<TIn, TOut>(this Expression<Func<TIn, TOut>> property) 
     where TIn: class 
{ 
    MemberExpression memberExpression = (MemberExpression)property.Body; 
    TIn instance = Expression.Lambda<Func<TIn>>(memberExpression.Expression).Compile()(); 
    return instance; 
} 

저는 모두에게 감사의 말을 전합니다.