littlecharva
littlecharva

Reputation: 4244

Pass a Func<T,bool> as a parameter using reflection?

I have a method:

public bool DoStuff<T>(T obj) {
  // Do Stuff
  return result;
}

And I need to pass that as a Func<T, bool> parameter to another method that I don't know at compile time. Let's say that method looks like:

public int Any(Func<int, bool> arg) {
}

Or

public int Any(Func<string, bool> arg) {
}

So I'm invoking that method like this:

return instance.GetType().InvokeMember(method.Name, BindingFlags.InvokeMethod, null, instance, args);

What I can't figure out is how to wrap up a reference to DoStuff as a Func<T,bool>, where I don't know T at compile time, but DO know it at runtime, and stuff it into an object[] to provide as the parameters to the method call.

If it helps, I'm writing an interpreter of a simple language. DoStuff will interpret a lambda expression in the simple language and the invoked methods will be .NET functions provided by the consumer of the interpreter.

Update

After following the link provided in the comments by Hans (thanks!) I've implemented the following:

Type delegateType = typeof(Func<,>).MakeGenericType(new []{argType, typeof(bool)});
MethodInfo delegatedMethod = this.GetType().GetMethod(nameof(DoStuff), BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance);
MethodInfo generic = delegatedMethod.MakeGenericMethod(argType);

Delegate myDelegate = Delegate.CreateDelegate(delegateType, this, generic);
var args = new object[] { myDelegate };

return instance.GetType().InvokeMember(method.Name, BindingFlags.InvokeMethod, null, instance, args);

But the InvokeMember call gives me System.MissingMethodException: 'Method 'MyDomain.Any' not found.'

When I inspect the myDelegate variable in Visual Studio it shows:

myDelegate = {Method = {Boolean DoStuff[Func`2](System.Func`2[System.Int32,System.Boolean])} 

It's the ONLY element in the args array, and the method signature I'm invoking is:

public int Any(Func<int, bool> arg)

instance is an instance of the class containing the Any method, and method is a MethodInfo for the Any method.

Upvotes: 0

Views: 796

Answers (1)

Lause
Lause

Reputation: 126

So here's some code that works:

public class AnyImplementer
{
   public int Any(Func<int, bool> func)
    {
        return func(10)? 1: 0;
    }

  
}

public class DoStuffer
{
    public bool DoStuff<T>(T obj)
    {
        return obj.ToString() != string.Empty;
    }

    public int a(Type argType, AnyImplementer anyImplementer)
    {
        Type delegateType = typeof(Func<,>).MakeGenericType(new[] { argType, typeof(bool) });
        MethodInfo delegatedMethod = this.GetType().GetMethod(nameof(DoStuff), BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance);
        MethodInfo generic = delegatedMethod.MakeGenericMethod(argType);

        Delegate myDelegate = Delegate.CreateDelegate(delegateType, this, generic);
        var args = new object[] { myDelegate };

        return (int)anyImplementer.GetType().InvokeMember("Any", BindingFlags.InvokeMethod, null, anyImplementer, args);
    }
}


public class Program
{
   
    public static void Main(string[] args)
    {
        DoStuffer DoStuffer = new DoStuffer();
        AnyImplementer anyImplementer = new AnyImplementer();
       Console.WriteLine(DoStuffer.a(typeof(int), anyImplementer));
       
    }

    
}

Also accessible at https://pastebin.com/raw/3UxN6Sn4 - The idea is (as based on OP's updates and related questions) to create wrap the method instance into an object using a delegate constructed out of the method info of the generic method group.

Upvotes: 1

Related Questions