递归ExpressionBody

时间:2018-04-05 05:40:26

标签: c# reflection

我拥有ChildAttributte的财产

public class AircraftFlight : BaseEntity
{
    [Child(FilterType.Equal, "ParentTypeId", 13)]
    public ICollection<ItemFileLink> Files { get; set; }
}

我创建表达式

Expression<Func<AircraftFlight, IEnumerable<ItemFileLink>>> q = 
    i => i.Files.Where(f => f.ParentTypeId == 13);

我的任务使用带有此参数的方法使用反射创建此表达式。转到T类型和查找属性(文件)。然后在属性文件调用方法Where上使用condition(ParentTypeId == inputText)

private Expression<Func<T, IEnumerable<TChild>>> ExpressionConstructor<T, TChild>(
    string prop (property Files),
    string propertyName (property ParentTypeId), 
    object inputText, 
    FilterType condition)
你能帮助别人吗?

1 个答案:

答案 0 :(得分:0)

以下是如何通过Expression API完全实现的。我已经添加了我的类假设的假设。如果存在偏差,则需要更改设置的表达式。

在进入代码之前,这似乎是相当静态的代码,似乎不需要反射。我想你有正确的理由走这条路。完全相同的事情也可以通过反射命名空间下的类来实现。

class AircraftFlight
{
    internal ICollection<ItemFileLink> Files { get; set; }
}

class ItemFileLink
{
    internal int ParentTypeId { get; set; }
}

static void Main(string[] args)
{
    Type aircraftFlightType = typeof(AircraftFlight); 
    Type itemFileLinkType = typeof(ItemFileLink);
    // Create object of desired type
    ParameterExpression aircraftFlightObject = Expression.Parameter(aircraftFlightType, "parameter");

    // Locate files property
    MemberExpression filesPropertyExpression = Expression.Property(aircraftFlightObject, "Files");

    // Getting where method call for Files property
    var whereMethod = new Func<IEnumerable<ItemFileLink>, Func<ItemFileLink, bool>, IEnumerable<ItemFileLink>>(Enumerable.Where);

    // Getting item types and parentId property
    ParameterExpression itemFileLinkExpression = Expression.Parameter(itemFileLinkType);
    Expression parentTypeIdExpression = Expression.Property(itemFileLinkExpression, "ParentTypeId");

    // Create the lambda for where method (your condition for where clause)
    var lambdaForWhere = Expression.Lambda(Expression.Equal(parentTypeIdExpression, Expression.Constant(13)), itemFileLinkExpression);

    // Create where method call
    var whereMethodGeneric = whereMethod.Method.GetGenericMethodDefinition().MakeGenericMethod(itemFileLinkType);
    MethodCallExpression whereCall = Expression.Call(null, whereMethodGeneric, filesPropertyExpression, lambdaForWhere);

    // Create parent object
    AircraftFlight aircraftFlight = new AircraftFlight();
    aircraftFlight.Files = new Collection<ItemFileLink>();
    aircraftFlight.Files.Add(new ItemFileLink { ParentTypeId = 1 });
    aircraftFlight.Files.Add(new ItemFileLink { ParentTypeId = 13 });
    aircraftFlight.Files.Add(new ItemFileLink { ParentTypeId = 1 });
    aircraftFlight.Files.Add(new ItemFileLink { ParentTypeId = 13 });
    aircraftFlight.Files.Add(new ItemFileLink { ParentTypeId = 1 });
    aircraftFlight.Files.Add(new ItemFileLink { ParentTypeId = 1 });

    // Invoke
    var result = Expression.Lambda(whereCall, aircraftFlightObject).Compile().DynamicInvoke(aircraftFlight);
}

更新: 如果您不知道Files属性的类型,则可以先在方法中创建原型,然后创建特定的泛型方法。以下代码可能有所帮助:

    // Prepare prototype where method
    var whereMethod = new Func<IEnumerable<object>, Func<object, bool>, IEnumerable<object>>(Enumerable.Where);

    // Prepare specific where method. itemFileLinkType can be replaced by any other type
    var whereMethodGeneric = whereMethod.Method.GetGenericMethodDefinition().MakeGenericMethod(itemFileLinkType);