표현식 트리를 가져 와서 문자열 표현과 같은 다른 형식으로 변환하는 것이 일반적입니다 (예 :이 질문과이 질문, 그리고 나는 Linq2Sql이 비슷한 것을한다고 생각한다).
대부분의 경우, 심지어 대부분의 경우에도 표현식 트리 변환은 항상 동일합니다. 즉 함수가있는 경우
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)과 같은 것을 사용할 수 있다고 생각합니다.
우수한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);
}
}
우선, 나는 퍼포먼스 히트를 일으키는 표현을 컴파일하는 것에 대한 당신의 가정이 실제로 현실로 펼쳐지지 않을 것이라고 생각합니다. 내 경험에 따르면 일반적인 "좋은"코드로 인해 문제가 발생하기 전에 성능 병목 현상을 일으키는 더 많은 요소 (데이터베이스 액세스, 네트워크 지연, 매우 빈약 한 알고리즘)가 있음을 보여줍니다. 조기 최적화는 모든 악의 근원이므로 응용 프로그램을 빌드하고 스트레스 테스트를 실행하여 실제 성능 병목 현상을 찾아 낼 수 있습니다.
그렇게 말하면, 사전 편집은 표현이 무엇으로 변환되는지에 달려 있다고 생각합니다. LINQ를 사용하여 SQL에 호출 할 수 있다는 것을 알고 있습니다.DataContext.GetCommand (Expression)검색하고DBCommand
그런 다음 캐시하고 재사용 할 수 있습니다.