在表达式树中的select中创建select

时间:2014-11-25 18:39:42

标签: c# reflection lambda expression-trees

如何使用表达式树创建以下内容? 假设claimsIQueryable

ClaimData
var lastNames = claims.Select(p1 => p1.Advisors.Select(p2 => p2.LastName));

示例类如下:

public class ClaimData
{
    public string name { get; set; }
    public IQueryable<AdvisorData> Advisors { get; set; }
    public IQueryable<ActionData> Actions { get; set; }
}

public class AdvisorData
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class ActionData
{
    public string Name { get; set; }
    public string Comment { get; set; }
}

假设我们不知道ClaimData的哪个属性(本例中的Advisors)或者我们想要选择哪个属性(本例中为LastName)。

我想创建选择器但是有困难。这是我尝试过的代码,但是不完整,我显然感到困惑

var property = typeof(ClaimData).GetProperties().Where(p =>
{
    var args = p.PropertyType.GetGenericArguments();
    if (args.Count() == 0) return false;
    var innerProperty = args.First().GetProperties().Where(pi => PropertyByAttributeFunc(pi, table, column));
    return innerProperty.Count() > 0;
}).First();

var parameterExp = Expression.Parameter(typeof(ClaimData), "p1");
var propertyExp = Expression.Property(parameterExp, property.Name);

var propertyType = property.PropertyType.GenericTypeArguments.First();
var parameterInnerExp = Expression.Parameter(propertyType, "p2");
var propertyInner = propertyType.GetProperties().Where(pi => PropertyByAttributeFunc(pi, table, column)).First();
var propertyInnerExp = Expression.Property(parameterInnerExp, propertyInner.Name);

var selectMethod = typeof(Queryable).GetMethods().Where(x => x.Name == "Select").First()
.MakeGenericMethod(property.PropertyType, typeof(string));

var genericFunc = typeof(Func<,>).MakeGenericType(property.PropertyType, typeof(string));
var genericInnerFunc = typeof(Func<,>).MakeGenericType(propertyType, typeof(string));

var innerLambda = Expression.Lambda(genericInnerFunc, propertyInnerExp, parameterInnerExp);

var expCall = Expression.Call(selectMethod, propertyExp, innerLambda);

不要担心这一行:

var propertyInner = propertyType.GetProperties().Where(pi => PropertyByAttributeFunc(pi, table, column)).First();

它只为我返回正确的属性。

由于

1 个答案:

答案 0 :(得分:1)

您的错误位于以下行:

var selectMethod = typeof(Queryable).GetMethods()
    .Where(x => x.Name == "Select").First()
    .MakeGenericMethod(property.PropertyType, typeof(string));

property.PropertyTypeIQueryable<AdvisorData>。应该是AdvisorDataSelect的第一个通用参数是在查询中查找一个项的类型,而不是整个IQueryable的类型。这意味着您的Select来电需要传递IQueryable<IQueryable<AdvisorData>>以匹配参数Select预期。

变化很简单:

var selectMethod = typeof(Queryable).GetMethods()
    .Where(x => x.Name == "Select").First()
    .MakeGenericMethod(property.PropertyType.GetGenericArguments()[0], 
        typeof(string));