List<T> 上的动态表达式

洛伦佐

鉴于以下类

public class ClassA
{
    public string StringProperty { get; set; }

    public List<ClassB> List { get; set; }
}

public class ClassB 
{
    public int IntProperty { get; set; }
}

我想动态创建一个如下所示的表达式

x => x.StringProperty == "X" && x.List.Any( y => y.IntProperty > 1 )

第一部分没问题(x.StringProperty == "X")。对于第二部分,我创建了一个对应的成员表达式x.List,现在需要

  1. 创建内部 lambda。要做到这一点,我需要知道它的类型y实际上是相同的内部类型x.List
  2. 对 x.List 表达式调用 Any 方法

关于第一点的任何提示?我如何获得 an 的类型 T IEnumerable<T>

编辑

我已尝试使用以下代码,但不幸的是它返回 null

//This expression will be x.List of my original sample 
MemberExpression expr = GetMemberExpression( property, pe );

Type innerType = expr.GetType()
                     .GetInterfaces()
                     .Where( t => t.IsGenericType == true && t.GetGenericTypeDefinition() == typeof( IEnumerable<> ) )
                     .Select( t => t.GetGenericArguments()[0] )
                     .SingleOrDefault();
沙纳托斯

给定的

private static readonly MethodInfo anyT = (from x in typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static)
                                            where x.Name == nameof(Enumerable.Any) && x.IsGenericMethod
                                            let gens = x.GetGenericArguments()
                                            where gens.Length == 1
                                            let pars = x.GetParameters()
                                            where pars.Length == 2 &&
                                                pars[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(gens[0]) &&
                                                pars[1].ParameterType == typeof(Func<,>).MakeGenericType(gens[0], typeof(bool))
                                            select x).Single();

// https://stackoverflow.com/a/906513/613130
private static IEnumerable<Type> GetGenericIEnumerables(Type type)
{
    return type.GetInterfaces()
                .Where(t => t.IsGenericType == true
                    && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                .Select(t => t.GetGenericArguments()[0]);
}

那么你就可以:

var parX = Expression.Parameter(typeof(ClassA), "x");

var list = Expression.Property(parX, nameof(ClassA.List));

var listType = list.Type;
var baseType = GetGenericIEnumerables(listType).First();

var parY = Expression.Parameter(baseType, "y");

var eq = Expression.Equal(
    Expression.Property(parX, nameof(ClassA.StringProperty)),
    Expression.Constant("X"));

var gt = Expression.GreaterThan(
    Expression.Property(parY, "IntProperty"),
    Expression.Constant(1));

var innerExpression = Expression.Lambda(gt, parY);

var any = Expression.Call(
    anyT.MakeGenericMethod(baseType),
    list,
    innerExpression);

var and = Expression.AndAlso(eq, any);

var outerExpression = Expression.Lambda<Func<ClassA, bool>>(and, parX);

var compiled = outerExpression.Compile();

var result = objs.Where(compiled).ToArray();

请注意,您不需要编译innerExpression:outerExpression.Compile()将为您做所有事情!

我使用的修改版本自IEnumerable <T>得到类型T找到TIEnumerable<T>

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章