Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I invoke a method through reflection with a lambda expression as a parameter?

I want to do this:

MethodInfo m = myList.GetType().GetMethod("ConvertAll", System.Reflection.BindingFlags.InvokeMethod).MakeGenericMethod(typeof(object));
List<object> myConvertedList = (List<object>)m.Invoke(myList, new object[]{ (t => (object)t)});

myList is a generic list of a specific type (unknown to the application), and I want to convert it to a list of objects to do some operations.

However this fails with this error: "Cannot convert lambda expression to type 'object' because it is not a delegate type"

Can you help me find what's wrong? Am I trying to do something that's not possible?

Is there some other way to achieve the same thing?

like image 910
juan Avatar asked Jan 12 '09 19:01

juan


People also ask

How do you pass a lambda function as a parameter in Java?

Passing Lambda Expressions as ArgumentsIf you pass an integer as an argument to a function, you must have an int or Integer parameter. If you are passing an instance of a class as a parameter, you must specify the class name or the object class as a parameter to hold the object.

Can you use ref and out parameters in lambda expression if declared outside?

Lambda expressions can make use of variables declared in a containing scope, i.e. outside of the expression itself. They cannot, however, use variables that are defined as ref or out parameters in an outer scope.

Can we use dynamic in lambda expression?

In 2010, the Dynamic Type was introduced and that gave us the ability to create dynamic lambda expressions.

What is a lambda expression how when do you use it?

A lambda expression is a short block of code which takes in parameters and returns a value. Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.


2 Answers

A lambda expression is convertible to either a delegate type or an expression tree with the right signature - but you need to specify which delegate type it is.

I think your code would be much simpler if you made this a generic method:

public static List<object> ConvertToListOfObjects<T>(List<T> list)
{
    return list.ConvertAll<object>(t => t);
}

Then you just need to find and invoke that method generically:

MethodInfo method = typeof(Foo).GetMethod("ConvertToListOfObjects",
    BindingFlags.Static | BindingFlags.Public);
Type listType = list.GetType().GetGenericArguments()[0];
MethodInfo concrete = method.MakeGenericMethod(new [] { listType });
List<object> objectList = (List<object>) concrete.Invoke(null, 
                                                   new object[]{list});

Complete example:

using System;
using System.Reflection;
using System.Collections.Generic;

class Test
{
    public static List<object> ConvertToListOfObjects<T>(List<T> list)
    {
        return list.ConvertAll<object>(t => t);
    }

    static void Main()
    {
        object list = new List<int> { 1, 2, 3, 4 };

        MethodInfo method = typeof(Test).GetMethod("ConvertToListOfObjects",
            BindingFlags.Static | BindingFlags.Public);
        Type listType = list.GetType().GetGenericArguments()[0];
        MethodInfo concrete = method.MakeGenericMethod(new [] { listType });
        List<object> objectList = (List<object>) concrete.Invoke(null,
                                                    new object[] {list});

        foreach (object o in objectList)
        {
            Console.WriteLine(o);
        }
    }
}
like image 95
Jon Skeet Avatar answered Oct 03 '22 00:10

Jon Skeet


A lambda forms a method group (basically this is a method identified by name (and scope) only. Since methods with the same name can be overloaded, a method group comprises several different members). This cannot always implicitly be converted to a delegate because a delegate is actually bound to a single method from within a method group. This plays a role with overloading.

Unfortunately, the same applies in your case. The remedy is to make an explicit delegate:

List<object> myConvertedList = (List<object>)m.Invoke(myList, new object[]{ new Func<YourType, object>(t => (object)t)});
like image 32
Konrad Rudolph Avatar answered Oct 03 '22 00:10

Konrad Rudolph