2011-10-14 15 views
5

Daje mi się do szaleństwa, próbując zrozumieć wyrażenia w LINQ. Każda pomoc jest bardzo doceniana (nawet mówienie mi, że jestem tu całkowicie bez bazy).Zagnieżdżone standardowe Lambdas w LINQ

Powiedzmy mam trzy klasy

public class Person 
{ 
    public string Name { get; set;} 
    public IEnumerable<PersonLocation> Locations { get; set;} 
    public IEnumerable<PersonEducation> Educations { get; set:} 
} 

public class PersonLocation 
{ 
    public string Name { get; set;} 
    public string Floor { get; set;} 
    public string Extension { get; set;} 
} 

public class PersonEducation 
{ 
    public string SchoolName { get; set;} 
    public string GraduationYear { get; set;} 
} 

Próbuję utworzyć metodę, która pobiera ciąg znaków, takich jak Locations.Name lub Locations.Floor lub Educations.SchoolName który będzie następnie utworzyć dynamiczny zapytania LINQ

IEnumerable<Person> people = GetAllPeople(); 
GetFilteredResults(people, "Location.Name", "San Francisco"); 
GetFilteredResults(people, "Location.Floor", "17"); 
GetFilteredResults(people, "Educations.SchoolName", "Northwestern"); 

GetFilteredResults(IEnumerable<Person> people, string ModelProperty, string Value) ten sposób powinien utworzyć wyraz która jest z grubsza równoważna people.Where(p => p.Locations.Any(pl => pl.Name == Value);

lH ave tej pracy, jeśli ModelProperty jest ciągiem znaków, tj people.Where (p => p.Name == Value) wygląda następująco:

string[] modelPropertyParts = ModelProperty.Split('.'); 
var prop = typeof(Person).GetProperty(modelPropertyParts[0]); 
var sourceParam = Expression.Parameter(typeof(Person), "person"); 
var expression = Expression.Equal(Expression.PropertyOrField(sourceParam, modelPropertyParts[0]), Expression.Constant(option.Name)); 
var whereSelector = Expression.Lambda<Func<Person, bool>>(orExp, sourceParam); 
return people.Where(whereSelector.Compile()); 

Oto co zostały odtwarzanie z do typu IEnumerable, ale po prostu nie mogę dostać wewnętrzna każdy, co wydaje się słuszne, podłączona do zewnętrznego Gdzie:

/*i.e. modelPropertyParts[0] = Locations & modelPropertyParts[1] = Name */ 
string[] modelPropertyParts = ModelProperty.Split('.'); 

var interiorProperty = prop.PropertyType.GetGenericArguments()[0]; 
var interiorParameter = Expression.Parameter(interiorProperty, "personlocation"); 
var interiorField = Expression.PropertyOrField(interiorParameter, modelPropertyParts[1]); 
var interiorExpression = Expression.Equal(interiorField, Expression.Constant(Value)); 
var innerLambda = Expression.Lambda<Func<PersonLocation, bool>>(interiorExpression, interiorParameter); 

var outerParameter = Expression.Parameter(typeof(Person), "person"); 
var outerField = Expression.PropertyOrField(outerParameter, modelPropertyParts[0]); 
var outerExpression = ?? 
var outerLambda == ?? 

return people.Where(outerLambda.Compile()); 

Odpowiedz

1

problemem jest to, że System.Linq.Enumerable.Any jest statyczną metodę rozszerzenia.

Twój outerExpression musi odwoływać System.Linq.Enumerable.Any(IEnumerable<T>, Func<T, bool>):

var outerExpression = Expression.Call(
    typeof(System.Linq.Enumerable), 
    "Any", 
    new Type[] { outerField.Type, innerLambda.Type }, 
    outerField, innerLambda); 

Spójrz na te linki, aby uzyskać więcej informacji:

+0

Niesamowite, dzięki! To w zasadzie działało, jedynym problemem jest to, że typ, który przekazujesz, jest nieprawidłowy. Powinien być wnętrze Właściwość zamiast typu (Osoba) –

+0

O tak, teraz widzę. Możesz poprawić odpowiedź (wspólnota wiki) –