Expression.MethodCallExpression将MemberExpression作为参数传递

时间:2018-11-19 17:39:46

标签: c# lambda linq-expressions

我正在尝试使用

上的方法调用来创建通用表达式
  

可枚举。包含

所以基本上我想实现这个简单的lambda

  

x => collection.Contains(x.SomeProperty)

到目前为止,我的代码如下:

ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "x");
MemberExpression memberExpression = Expression.Property(parameterExpression, propertyName);

MethodCallExpression methodCall = Expression.Call(
    typeof(Enumerable),
    "Contains",
    new Type[] { typeof(Object) },
    Expression.Constant(new Object[] { 1, 2, 3 }),
    memberExpression
);

但是它会转储

  

InvalidOperationException:类型'System.Linq.Enumerable'上的通用方法'Contains'与提供的类型不兼容
  论点和论点。如果
,则不应该提供类型参数   方法是非泛型的

如果我只是通过paramterExpression,它就可以正常工作,但是那不是我想要的。

现在是我的问题。有没有办法将Memberexpression传递给Contains mehtod调用?

1 个答案:

答案 0 :(得分:2)

这取决于Type中的memberExpression,而后者又取决于所访问的属性的类型。

例如以下作品:

void Main()
{
    string propertyName = "ObjectProperty";
    ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "x");
    MemberExpression memberExpression = Expression.Property(parameterExpression, propertyName);
    MethodCallExpression methodCall = Expression.Call(
        typeof(Enumerable),
        "Contains",
        new Type[] { typeof(object) },
        Expression.Constant(new Object[] { 1, 2, 3 }),
        memberExpression
    );

    Console.WriteLine(Expression.Lambda<Func<T, bool>>(methodCall, parameterExpression).Compile()(new T()));
}

public class T
{
    public object ObjectProperty => 2;
    public int IntProperty => 4;
}

以下内容不:

void Main()
{
    string propertyName = "IntProperty";
    ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "x");
    MemberExpression memberExpression = Expression.Property(parameterExpression, propertyName);
    MethodCallExpression methodCall = Expression.Call(
        typeof(Enumerable),
        "Contains",
        new Type[] { typeof(object) },
        Expression.Constant(new Object[] { 1, 2, 3 }),
        memberExpression
    );

    Console.WriteLine(Expression.Lambda<Func<T, bool>>(methodCall, parameterExpression).Compile()(new T()));
}

public class T
{
    public object ObjectProperty => 2;
    public int IntProperty => 4;
}

您还可以使用new Type[] { memberExpression.Type }代替new Type[] { typeof(object) }使代码适应属性的类型,尽管您还需要具有参数表达式的类型(在这种情况下,{ {1}}))匹配。

请注意,只有当隐式类型转换是从有问题的类型(Constant(new Object[] {...}派生的引用类型)时,您才能在此处进行隐式转换,因此返回objectstring的属性就可以了(尽管在检查它是否包含在Uri数组中时显然总是错误的),但是返回1, 2, 3的属性不是拳击转换,不是向上引用的引用。