0

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.

littlecharva
  • 4,224
  • 8
  • 45
  • 52
  • Well, that's not what generics are designed for. I guess, you might want to look for a solution using [`dynamic`](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic) ? – Fildor Aug 26 '20 at 09:45
  • 1
    https://stackoverflow.com/questions/13933565/how-do-i-make-a-generic-delegate-using-a-type-in-c – Hans Passant Aug 26 '20 at 09:49
  • @littlecharva could you verify that https://pastebin.com/3UxN6Sn4 is a viable example of what you're trying to do? – Lause Aug 26 '20 at 11:17
  • @Lause Yes, that's it. I created a new project and pasted in your code, which works perfectly. I then started replacing your code with my code and discovered the problem: in my code I was passing Func as the argType, when I should have been passing int. It now works perfectly! Do you want to post a link to your pastebin as the answer and I'll accept it. Thanks so much for helping me find my mistake! – littlecharva Aug 26 '20 at 13:19

1 Answers1

1

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.

Lause
  • 126
  • 5