2

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 implement 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!

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Wow, you're quick! I was going to log in tomorrow and see if anyone replied :)
So, that would be as another ParameterExpression then, right? It is indeed, not a constant in the final version.
@mnield - you already have the parameter-expression; you just didn't include it in the call to Lambda. It should be Expression.Lambda(methodCall, objectListParam, idList) (or the other way around); equally, you need to pass in the actual list to invoke: .DynamicInvoke(entityList,idList)
OK, yeah. Got it, thanks! It now compiles like a charm. Unfortunately, DynamicInvoke() now chokes and says Object of type 'System.Collections.Generic.List1[PoCDynamicLambda.Program+TestClass]' cannot be converted to type 'PoCDynamicLambda.Program+TestClass'.` I guess one of my types must be incorrect :$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.