views:

218

answers:

4

I am loading some assemblies at run time and invoking methods on them using Reflections (MethodInfo.Invoke).

Now I want to make these calls asynchronous. So I am thinking of using Delegate.BeginInvoke(). But I am not sure how to create delegate instance by providing function name at run-time. (All examples I see have delegate instance target resolved at compile time itself.) I have a MethodInfo object containing the method to be invoked. Is there a way to do this?

   public void Invocation(Object[] inputObjs)
    {
        public delegate string DelegateMethodInfo(int num);

        Assembly assm = Assembly.Load(assemblyName);
        Type type = assm.GetType(className);
        Type[] ctorParams = new Type[0];
        Object[] objs = new Object[0];

        ConstructorInfo ctorInf = type.GetConstructor(ctorParams);
        Object classObj = ctorInf.Invoke(objs);
        MethodInfo methodInf = type.GetMethod(methodName);

        // Need asynchronous invocation.
        //Object retObj = methodInf.Invoke(classObj, inputObjs);

        DelegateMethodInfo del = new DelegateMethodInfo(???); // How to instantiate the delegate???
        del.BeginInvoke((int)inputObjs[0], null, null);
    }
+2  A: 

You can use Delegate.CreateDelegate - but you'll need to know the signature so that you've got an appropriate type of delegate to create. That's slightly tricky when you've basically just got the MethodInfo :( Even worse, there's no equivalent of Delegate.DynamicInvoke for asynchronous execution.

To be honest, the simplest thing would be to start a new thread pool job which invoked the method:

ThreadPool.QueueUserWorkItem(delegate { methodInf.Invoke(classObj, inputObjs);});
Jon Skeet
Would it be accurate to say that using ThreadPool.QueueUserWorkItem over Delegate.CreateDelegate is "moving the asynchronous execution higher in the call stack"? Seems like a better approach to me anyway.
Jon Schoning
That would be a fairly reasonable description, yes.
Jon Skeet
+1  A: 

Just use a lambda expression that wraps the call to methodInf.Invoke. The resulting delegate is of type DelegateMethodInfo.

Dario
A: 

Have you looked at using MethodInvoker (The delegate, not the class) and not trying to create an additional delegate? By using an anonymous method with this, you may be able to pull off what you need. Or I may be smoking crack. But, basically, MethodInvoker acts as a standard parameterless delegate then in the anon method, you pass your parameters to MethodInvoker's anonmous code. I've used it in WinForms to do Form.BeginInvoke without needing to create delegates left and right. If need to and you can wait, respond to me and I'll get you sample code tonight (I'm on US West Coast... GMT -8).

Jim Leonardo
A: 

This is similar to the other answers, but you can create a new Func and assign the methodInf.Invoke method to it. Here's an example

class Other
{
    public void Stuff()
    { Console.WriteLine("stuff"); }
}

static void Main(string[] args)
{
    var constructor = typeof(Other).GetConstructor(new Type[0]);
    var obj = constructor.Invoke(null);

    var method = typeof(Other).GetMethods().First();
    Func<object, object[], object> delegate = method.Invoke;
    delegate.BeginInvoke(obj, null, null, null);

    Console.ReadLine();
}

What it's doing is creating a new variable of type Func<object, object[], object>, which matches the signature of MethodInfo.Invoke. It then gets a reference to the actual invoke method on your object, and sticks that reference in the variable.

Because Func<> is a delegate type, you can then use BeginInvoke

Orion Edwards