2013-06-17 6 views
1

이것은 모두 Compile 방법 Expression 유형에 관한 것입니다. 내가 늦게까지 왔기 때문에 미안해. 필자는 실행 코드의 동적 수정을 가능하게하기 위해 표현식 작성에 대해 읽었습니다. 다양한 입력/환경 (주어진 상수/매개 변수/멤버 표현식에 대해 다른 값을 말하면)에 대해 주어진 표현식 트리에서 람다 식을 방출하는 것에 관해서는 나에게 의미가 있습니다. 나는 환경에 변화가 없다면 표현식 트리에서 생성/컴파일 된 람다를 캐시 (재사용) 할 수 있다면 이상적이라고 생각한다.표현 트리 및 컴파일 방법

질문 : 환경에 변화가 없더라도 CLR은 항상 람다 식을 방출합니까? 그렇다면 환경에 변화가 없다면 람다에서 표현을 편집하는 것을 피하는 것이 가장 좋습니다.

+1

나는 당신이 표현 나무를 얼마나 정확하게 사용하고 있는지에 의존한다라고 생각한다. 당신이 그들을 사용하는 방법을 상상하는 구체적인 예를 추가 할 수 있을까요? – svick

답변

2

람다 식은 코드를 표현하는 단지 방법 일 뿐이며, 이것을 호출하고, 호출하고, 이러한 인수를 비교하고, 무언가를 반환합니다. 코드 편집기에서 JIT를 수행하는 것과 거의 같은 방식으로 또는 JIT가 IL에서 수행합니다.

Compile은 특정 람다 식에서 대리자를 방출합니다. 일단 람다를 델리게이트로 컴파일하면 델리게이트는 변경되지 않습니다 (람다는 변경되지 않기 때문에 변경되지 않습니다).

위임자가 인수를 허용하거나 개체의 메서드를 호출 할 수 없다는 것을 의미하지 않습니다. 이는 위임자의 일리노이가 변경되지 않는다는 것을 의미합니다. 그리고 네, 컴파일 된 대리자 인스턴스를 캐시 할 수 있습니다.

2

CLR은 람다 식을 캐시하지 않으므로 매번 Compile()이 새로운 대리자를 반환합니다. 이런 일을 통해

그러나 캐시 용이해야한다 :

Compile() 새로운 대표 매번 돌아갑니다 호출
public Func<T> Get<T>(Expression<Func<T>> expression) 
{ 
    string key = expression.Body.ToString(); 

    Func<T> result; 
    if (!_cache.TryGetValue(key, out result)) { 
     result = expression.Compile(); 
     _cache.Add(key, result); 
    } 

    return result; 
} 
+1

평등을 비교하기 위해'ToString()'을 사용하는 것이 허약하다고 생각합니다. 예를 들어'(x, x) => (x + x)'의 문자열 표현을 갖는 두 개의 표현식을 만들 수 있지만 다른 결과를 반환합니다. 대안 (적절히 구조적으로 '표현식'을 비교하는 것)은 사소하지 않습니다. – svick

+0

또한 일반 필드 ('_cache'는'Dictionary >'가 될 수 없으므로)를 사용할 수 없으므로 코드가 실제로 작동하지 않습니다. 그러나 그것은 캐스팅으로 쉽게 고칠 수 있습니다. – svick

+0

예. 그보다 더 많은 종류의 의사 코드입니다. – andreister

0

, 때마다 새로운 MSIL 코드가 방출된다. MSIL 코드가 가비지 수집 대상이 아니기 때문에 느리며 메모리 누수가 발생합니다 (). 나는 캐시 된 컴파일을 제공하는 라이브러리를 만들었는데, 실제로 식의 구조를 올바르게 비교하고 캐시 된 대리자를 다시 사용할 수 있습니다. 모든 상수와 클로저는 자동으로 매개 변수로 대체되며 외부 closure에서 대리자에 다시 삽입됩니다. 누출 된 메모리를 피하고 훨씬 빠릅니다. 그것을 여기에서 조사해라 : https://github.com/Miaplaza/expression-utils