2010-06-17 2 views
4

표현식 트리를 사용하여 문자열 표현 (예 : this questionthis question과 같은 다른 형식으로 변환하면 Linq2Sql과 비슷한 기능을 수행 할 수 있습니다). 난 항상에 대해 동일한 결과를 반환합니다 다음 함수Lambda 표현식 트리 변환을 상수로 프리 컴파일?

public string GenerateSomeSql(Expression<Func<TResult, TProperty>> expression) 

같은 인수를 모든 통화를 경우 많은 경우에

, 아마도 대부분의 경우는 식 트리 변환은 항상, 즉 동일합니다 예 : 시간이 런타임이 지속적으로 재 계산에서 낭비를 제외하고

GenerateSomeSql(x => x.Age) //suppose this will always return "select Age from Person" 
GenerateSomeSql(x => x.Ssn) //suppose this will always return "select Ssn from Person" 

그래서 본질적으로 특정 인수를 사용하여 함수 호출은, 정말 그냥 상수이다.

변환을 실행하면 눈에 띄는 성능 저하가 발생하기에 충분히 복잡하다고 가정하면 함수 호출을 실제 상수로 미리 컴파일 할 수있는 방법이 있습니까?

편집 C# 자체 내에서이 작업을 수행 할 방법이 없다고합니다. C#에서 가장 가까운 것은 아마도 받아 들인 대답 일 것이다 (물론 캐싱 자체가 재생성보다 느리지는 않았 으면 좋겠다). 진정한 상수로 변환하려면 컴파일 후 바이트 코드를 수정하기 위해 모노 세실 (mono-cecil)과 같은 것을 사용할 수 있다고 생각합니다.

답변

2

우수한 LINQ IQueryable Toolkit 프로젝트에는 사용자가 설명한 것과 유사한 작업을 수행하는 쿼리 캐시가 있습니다. 여기에는 두 표현식의 계층 구조를 탐색하고 두식이 같은지 여부를 결정하는 ExpressionComparer 클래스가 들어 있습니다. 이 기술은 매개 변수화 및 중복 조인 제거에 대한 공통 속성에 대한 참조를 수집하는데도 사용됩니다.

표현식 해싱 전략을 수립하면 처리 된 표현식의 결과를 사전에 저장하여 나중에 다시 사용할 수 있습니다.

귀하의 방법은 다음과 같이 보일 것입니다 :

private readonly IDictionary<Expression, string> _cache 
    = new Dictionary<Expression, string>(new ExpressionEqualityComparer()); 

public string GenerateSomeSql(Expression<Func<TResult, TProperty>> expression) 
{ 
    string sql; 
    if (!_cache.TryGetValue(expression, out sql)) 
    { 
     //process expression 
     _cache.Add(expression, sql); 
    } 
    return sql; 
} 

class ExpressionEqualityComparer : IEqualityComparer<Expression> 
{ 
    public bool Equals(Expression x, Expression y) 
    { 
     return ExpressionComparer.AreEqual(x, y); 
    } 

    public int GetHashCode(Expression obj) 
    { 
     return ExpressionHasher.GetHash(obj); 
    } 
} 
1

우선, 퍼포먼스 히트를 일으키는 표현식을 컴파일하는 것에 대한 귀하의 가정은 실제로 현실로 펼쳐지지 않을 것이라고 생각합니다. 내 경험에 따르면 일반적인 "좋은"코드로 인해 문제가 발생하기 전에 성능 병목 현상을 일으키는 더 많은 요소 (데이터베이스 액세스, 네트워크 지연, 매우 빈약 한 알고리즘)가 있음을 보여줍니다. 조기 최적화는 모든 악의 근원이므로 응용 프로그램을 빌드하고 스트레스 테스트를 실행하여 실제 성능 병목 현상을 찾아 낼 수 있습니다.

그렇다면 사전 컴파일은 표현식이 무엇으로 변환되는지에 달려 있다고 생각합니다. LINQ to SQL을 사용하면 DataContext.GetCommand(Expression)을 호출하고 DBCommand을 검색 할 수 있으며 캐시하고 다시 사용할 수 있습니다.

관련 문제