표현 트리를 수정하는 것이 실제적인 사례를 말해 줄 수 있습니까?
엄밀히가 불변으로, 우리는 식 트리를 수정하지 말하기 (외부에서 볼 때, 적어도, 그것은 memoise 값하거나 변경 가능한 개인 상태가없는 내부적 않는 어떤 약속도 없다). 그것들은 불변이므로 정확히 우리가 가지고있는 표현식 트리를 기반으로 새로운 표현식 트리를 만들려면 방문자 패턴이 많은 노드를 변경할 수 없습니다. 우리가 불변 객체를 수정해야만하는 가장 가까운 것).
Linq 자체에서 몇 가지를 찾을 수 있습니다.
가장 간단한 Linq 공급자는 메모리의 열거 형 개체에서 작동하는 linq-to-objects 공급자입니다.
열거 형을 직접적으로 IEnumerable<T>
개체로 받으면 대부분의 프로그래머가 대부분의 메서드를 최적화되지 않은 버전으로 쉽게 작성할 수 있다는 점에서 매우 간단합니다. 예 : Where
은 다음과 같습니다 등등
foreach (T item in source)
if (pred(item))
yield return item;
합니다. 그러나 EnumerableQueryable
은 IQueryable<T>
버전을 구현하면 어떨까요? EnumerableQueryable
은 IEnumerable<T>
을 감싸기 때문에 관련된 하나 이상의 열거 가능한 객체에 대해 원하는 작업을 수행 할 수 있지만 우리는 해당 작업을 IQueryable<T>
및 선택자, 조건 자 등의 다른 표현식으로 설명하는 표현식을 사용합니다. 여기서 필요한 것은 설명입니다. 셀렉터 등, 술어 IEnumerable<T>
의 관점에서 그 대리자 동작
System.Linq.EnumerableRewriter
의 ExpressionVisitor
구현 정확히 같은 재 기입을 수행하고, 그 결과는 단순히 컴파일되고 실행될 수있다.
System.Linq.Expressions
내에는 다양한 목적으로 ExpressionVisitor
의 구현이 몇 가지 있습니다. 한 가지 예는 인터프리터 형식의 컴파일은 인용 된 표현식에서 호이 스팅 된 변수를 직접 처리 할 수 없으므로 방문자가 사전을 사용하여 인덱스로 작업하도록 다시 작성합니다.
다른 표현식을 만드는 것뿐만 아니라 ExpressionVisitor
도 다른 결과를 생성 할 수 있습니다. 다시 System.Linq.Expressions
에는 디버그 문자열과 함께 내부 예제가 자체적으로 포함되어 있고 문제의 식을 방문하여 많은 식 유형에 대해 ToString()
이 작동합니다.
이것은 데이터베이스 쿼리 linq 공급자가 식을 SQL 쿼리로 바꾸는 데 사용하는 방법 일 수 있습니다 (그래도 될 필요는 없지만).
언제 내가 그 중 어떤 것을 사용해야하는지 어떻게 알 수 있습니까?
이러한 방법의 기본 구현은 것입니다 : 표현이 자식 표현이없는 경우
- (예를 들어
Expression.Constant()
의 결과) 그때는 다시 노드를 반환합니다.
- 그렇지 않으면 모든 하위 식을 방문한 다음 해당 식에
Update
을 호출하고 결과를 다시 전달합니다. Update
은 새로운 자식이있는 동일한 유형의 새 노드를 차례로 반환하거나 자식 노드가 변경되지 않은 경우 동일한 노드를 다시 반환합니다.
이와 같이, 용도에 관계없이 노드를 명시 적으로 조작해야한다는 것을 모를 경우 변경하지 않아도됩니다. 또한 부분 변경을 위해 노드의 새 버전을 얻는 편리한 방법은 Update
입니다. 그러나 "당신의 목적이 무엇이든"은 물론 유스 케이스에 달려 있음을 의미합니다. 가장 일반적인 경우는 하나 또는 두 개의 표현식 유형이 무시를 필요로하거나, 모두 또는 거의 모두가 필요로하는 것과 같이 하나의 극단 또는 다른 것으로 갈 것입니다. 당신은 그것의 단계와 변수 또는 캐치 블록에 대한 TryExpression
모두에게 ReadOnlyCollection
같은 BlockExpression
에서 아이들이 그 노드의 자식을 검사하는 경우
(한 가지주의해야 할 점은, 당신은 단지 때때로 다음의 경우 그 아이가 변경됩니다 당신은 자신을 결함으로 확인하는 것이 가장 좋습니다. [최근에 수정되었지만 아직 출시 된 버전이 아닙니다] 동일한 자식을 원래 ReadOnlyCollection
과 다른 컬렉션에 Update
에게 전달하면 새로운 표현식 불필요하게 만들어져 나무 위로 올라가는 효과가 있습니다. 일반적으로 무해하지만 시간과 기억이 낭비됩니다.
트리 구조를 수정하려면 방문자가이를 달성하기위한 매우 표준적인 기술, 특히 변경 불가능한 트리의 경우가 많습니다. 이러한 방문자에 대한 기본 클래스를 제공합니다. 새 노드를 변경하고 반환해야하는 노드 유형의 메소드 만 대체합니다. 방문자는 전체적으로 점진적으로 새 트리를 만듭니다. –
@LucasTrzesniewski 이것은 내가 이미 알아 낸 것입니다 (노드 유형이 없으면이 사실을 알지 못했습니다). 저는 전에 가질 수있는 것에 관심이 있으며 무엇이 나올지에 관심이 있습니다. 어떤 종류의 표현 트리가 무엇에서 무엇으로 수정되어야 하는가? 이것은 누락 된 링크입니다. – t3chb0t
ㅎ, 대답은 * 당신이해야 할 일이 무엇이든합니다. 표현식 트리는 수정이 필요하지 않습니다. * 어떤 이유로 든 수정해야 할 수도 있습니다. 실제 예제를 보려면 [LINQKit] (https://github.com/scottksmith95/LINQKit)을 참조하십시오 (AsExpandable이 표현식을 다시 작성합니다). –