문제
프로젝트에서 Lambda Expressions를 사용하여 타사 쿼리 API에 매핑하려고합니다. 그래서 나는 표현 트리를 손으로 구문 분석하고 있습니다.
내가 람다 표현을 전달하면 :
p => p.Title == "title"
모든 것이 작동합니다.
그러나 내 람다 표현이 다음과 같습니다.
p => p.Title == myaspdropdown.SelectedValue
.NET 디버거를 사용하여 해당 funciton의 실제 값이 표시되지 않습니다. 대신 나는 다음과 같은 것을 본다.
p => p.Title = (value(ASP.usercontrols_myaspusercontrol_ascx).myaspdropdown.SelectedValue)
무엇을 제공합니까? 그리고 표현의 오른쪽을 끈으로 잡으려고 할 때 (value(ASP.usercontrols_myaspusercontrol_ascx).myaspdropdown.SelectedValue)
실제 값 대신. 실제 가치는 어떻게 얻습니까?
해결책
람다 표현식을 발현 트리로 다룰 때 실행 가능한 코드가 없음을 기억하십시오. 오히려 당신은 당신이 쓴 표현을 구성하는 표현식 요소를 가지고 있습니다.
Charlie Calvert가 있습니다 좋은 게시물 그것은 이것에 대해 자세히 논의합니다. 디버깅 표현식을 위해 Expression Visualiser를 사용하는 예가 포함되어 있습니다.
귀하의 경우, 평등 표현의 8 번째 측면의 가치를 얻으려면 새로운 람다 표현식을 만들어 컴파일 한 다음 호출해야합니다.
나는 이것의 빠른 예를 함께 해킹했습니다 - 그것이 당신이 필요한 것을 전달하기를 바랍니다.
public class Class1
{
public string Selection { get; set; }
public void Sample()
{
Selection = "Example";
Example<Book, bool>(p => p.Title == Selection);
}
public void Example<T,TResult>(Expression<Func<T,TResult>> exp)
{
BinaryExpression equality = (BinaryExpression)exp.Body;
Debug.Assert(equality.NodeType == ExpressionType.Equal);
// Note that you need to know the type of the rhs of the equality
var accessorExpression = Expression.Lambda<Func<string>>(equality.Right);
Func<string> accessor = accessorExpression.Compile();
var value = accessor();
Debug.Assert(value == Selection);
}
}
public class Book
{
public string Title { get; set; }
}
다른 팁
실제 값을 얻으려면 표현식 트리의 논리를 컨텍스트에 어떤 컨텍스트에 적용해야합니다.
표현 나무의 요점은 그들이 논리 표현식을 평가하기보다는 데이터로서. 람다 표현이 진정으로 의미하는 바를 해결해야합니다. 이는 로컬 데이터에 대해 일부를 평가하는 것을 의미 할 수 있습니다. 직접 결정해야합니다. 표현 나무는 매우 강력하지만 구문 분석하고 사용하는 것은 간단한 문제는 아닙니다. (LINQ 제공 업체를 작성한 사람에게 물어보세요 ... Frans Bouma는 여러 번 어려움을 겪었습니다.)
Bevan에게 똑같은 문제로 어려움을 겪고 있습니다. 확장에서 다음은 값을 추출하는 데 사용할 수있는 일반적인 패턴입니다 (쿼리 엔진에서 사용).
[TestFixture]
public class TestClass
{
[Test]
public void TEst()
{
var user = new User {Id = 123};
var idToSearch = user.Id;
var query = Creator.CreateQuery<User>()
.Where(x => x.Id == idToSearch);
}
}
public class Query<T>
{
public Query<T> Where(Expression<Func<T, object>> filter)
{
var rightValue = GenericHelper.GetVariableValue(((BinaryExpression)((UnaryExpression)filter.Body).Operand).Right.Type, ((BinaryExpression)((UnaryExpression)filter.Body).Operand).Right);
Console.WriteLine(rightValue);
return this;
}
}
internal class GenericHelper
{
internal static object GetVariableValue(Type variableType, Expression expression)
{
var targetMethodInfo = typeof(InvokeGeneric).GetMethod("GetVariableValue");
var genericTargetCall = targetMethodInfo.MakeGenericMethod(variableType);
return genericTargetCall.Invoke(new InvokeGeneric(), new[] { expression });
}
}
internal class InvokeGeneric
{
public T GetVariableValue<T>(Expression expression) where T : class
{
var accessorExpression = Expression.Lambda<Func<T>>(expression);
var accessor = accessorExpression.Compile();
return accessor();
}
}
이해가 잘 모르겠습니다. 당신은 어디에서 "보고 있습니까? 디자인 시간 또는 런타임입니까? Lambda 표현은 본질적으로 익명의 대표로 생각 될 수 있으며, 이연된 실행과 함께 작동합니다. 따라서 실행 후 그 라인이 통과 될 때까지 할당 된 값을 볼 수 없어야합니다.
나는 그것이 당신이 실제로 당신이 의미하는 바라고 생각하지 않습니다 ... 당신이 질문을 조금 명확히한다면 아마도 내가 도울 수 있습니다 :)