0

현재 동적 표현식을 만드는 중입니다. 다음 시나리오를 사용하고 있습니다. 주어진Expression Tree 로컬 변수를 캡처하는 방법

:

public class planet { 
    public string name { get;set; } 
} 

class someTestClass { 
    [Test] 
    public void Planet_Exists_Statically(){ 
     var planetName = "earth"; 
     var planets = new List<planet> {new planet {name = planetName}}; 
     var found = planets.Exists(MakePredicate(planetName)); 
     Assert.IsTrue(found); 
    } 

    [Test] 
    public void Planet_Exists_Statically(){ 
     var planetName = "earth"; 
     var planets = new List<planet> {new planet {name = planetName}}; 
     var found = planets.Exists(MakeDynamicPredicate(planetName)); 
     Assert.IsTrue(found); 
    } 

    private Predicate<planet> MakePredicate(string planetName){ 
     Expression<Predicate<planet>> pred = p => p.name == planetName; 
     return pred.Compile(); 
    } 

    private Predicate<planet> MakeDynamicPredicate(string planetName){ 
     var parm = Expression.Parameter(typeof(planet), "p") 
     var pred = Expression.Lambda<Predicate<planet>>(
        Expression.ReferenceEqual(
         Expression.Property(parm, typeof(planet), "name"), 
         **???WHAT GOES HERE???**, 
         parm); 
     return pred.Compile(); 
    } 
} 

그래서 내 문제는 내가 술어가 MakePredicate 기능에 의해 생성 된 것과 같도록 MakeDynamicPredicate에서 반환받을 수 없다는 것입니다.

은 내가 reply post from Jon Skeet를 읽을 수 있지만 어떤 도움을 크게 감상 할 수

... 로컬 변수를 캡처되도록 constantExpression을 구현하는 방법을 이해하지 않습니다.

추가 정보 : 앞으로 사용할 수있는 클래스를 알지 못해 결국보다 일반적인 것으로 추상화 될 것입니다.

+0

일부 게시물 (Jon Skeet의 게시물)을 언급 한 경우 링크를 사용하면 도움이됩니다. – svick

+0

미안 해요. 전 가서 Jon의 이름을 그가 대답 한 – ermagana

답변

1

실제로 로컬 변수를 캡처 할 필요가없는 경우 Expression.Constant(planetName)을 사용할 수 있습니다.

예를 들어 MakeDynamicPredicate("Pluto")과 같이 호출하면 생성 된 표현식은 마치 p => p.name == "Pluto"처럼 작성됩니다.

+0

에 대한 답변에 대한 링크로 만들었지 만, p => p.name == planetName으로 표현식을 반환하고 싶습니다. – ermagana

+0

@ermagana 이유는 무엇입니까? 그것은 당신의 사건에 어떤 차이도 만들지 않을 것입니다. – svick

+0

이 특정 인스턴스가 차이를 만들지는 않겠지 만 좀 더 일반적인 디자인을 향해 나아가고 있습니다. 또한 가능해야하기 때문에 일반적으로 어떻게해야하는지 알고 싶습니다. 적어도 알다. – ermagana

1

Jon의 글에서 읽을 수 있듯이 변수를 저장할 개체가 필요합니다. MakePredicate의 경우 컴파일러에서 생성되며 MakeDynamicPredicate은 직접 처리해야합니다. 우선 변수 값 저장을위한 클래스가 필요합니다.

 

class someTestClass { 
... 
     private class ValueHolder 
     { 
      public string Value; 
     } 
... 
} 
 

지금 당신은 당신의 planetName ValueHolder의 인스턴스에 투입하고 술어 표현식에서 사용하기위한 회원 액세스 표현을합니다.

 

private Predicate MakeDynamicPredicate(string planetName){ 
 var valueHolder = new ValueHolder { Value = value }; var valueExpr = Expression.MakeMemberAccess( Expression.Constant(valueHolder), valueHolder.GetType().GetField("Value"));  
     var parm = Expression.Parameter(typeof(planet), "p") 
     var pred = Expression.Lambda>(
        Expression.ReferenceEqual(
         Expression.Property(parm, typeof(planet), "name"), 
         valueExpr, 
         parm); 

} 
 

P. 다양한 epxress가 어떻게 생성되는지 더 잘 이해하기 위해 컴파일러가 생성 한 코드 (예 : ILSpy)를 살펴 보는 것이 좋습니다.