Parameter Not In Scope when Compiling LambdaExpression
I'm doing a bit of work using reflection and want to create a LambdaExpression that I can run against a List<T>
collection and intersect with a HashSet<int>
collection to find any matches.
My problem is that T
does not imp开发者_StackOverflowlement a common base class or interface, hence the reflection on types and a requirement tp programatically build a Lambda expression.
I'f I knew my types, what I wnat to execute is:
List<TestClass> entityList = GetOriginalList();
HashSet<int> idList = new HashSet<int>() { 1, 2, 3, 4 };
List<TestClass> filteredList = entityList.Where(o => idList.Contains(o.Id)).ToList();
I started mocking up a way to do this using LambdaExpression
, but I can't get the thing to compile and can't seem to figure out how to do what it wants (i.e. feed in the variable for the HashSet<int>
). My bodged attempt is below, does anyone have any suggestions as to how to get the LambdaExpression
to compile, and how to actually execute it getting a List<myObject>
out at the other end?
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace PoCDynamicLambda
{
class Program
{
class TestClass
{
private int _id;
private string _value;
public int Id { get { return this._id; } set { this._id = value; } }
public string Value { get { return this._value; } set { this._value = value; } }
public TestClass(int id, string value)
{
this._id = id;
this._value = value;
}
}
static void Main(string[] args)
{
List<TestClass> entityList = new List<TestClass>()
{
new TestClass(1, "One"),
new TestClass(2, "Two"),
new TestClass(3, "Three")
};
HashSet<int> idList = new HashSet<int>() { 2, 3, 5 };
MethodInfo containsMethod = idList.GetType().GetMethod("Contains");
ParameterExpression idListParam = Expression.Parameter(idList.GetType(), "idList");
ParameterExpression objectListParam = Expression.Parameter(typeof(TestClass), "entityList");
PropertyInfo idProperty = typeof(TestClass).GetProperty("Id");
MemberExpression idMember = Expression.Property(objectListParam, idProperty);
MethodCallExpression methodCall = Expression.Call(idListParam, containsMethod, idMember);
LambdaExpression le = Expression.Lambda(methodCall, objectListParam);
Console.WriteLine(le); // returns {entityList => idList.Contains(entityList.Id)}
le.Compile(); // Error here
Console.WriteLine(le.Compile().DynamicInvoke(entityList));
Console.ReadLine();
}
}
}
Thanks in advance!
You need to include idList
in the call to Expression.Lambda
, and supply an argument in the final invoke (DynamicInvoke
in your example). Or if it is meant to be fixed at {2,3,5}, replace idList
with an Expression.Constant
.
Note that if you want to get the performance, you need to use typed invoke, not DynamicInvoke
.
精彩评论