CreateDelegate refuses to create delegates like methods

This is a kind of continuation of the previous topic. I am creating a little wrapper to do upcalls for dynamically typed methods provided by my users. The circuit works well ... but only for static methods. While CreateDelegate should work as well, for example when used with these, it throws a "binding error" if the method's isStatic flag is false (in fact, since I have a throw on on error flag, it returns null). Here is a sample code. in which you can see it.

using System; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Reflection; 

namespace ConsoleApplication4 
{ 
    delegate void myFoo(int i, string s);
    delegate void myNull();

    internal class Callable
    {
        internal int nParams;
        internal Type[] ptypes;
        internal Delegate cb;
        internal static Type[] actions = { typeof(Action), typeof(Action<>), typeof(Action<,>), typeof(Action<,,>), typeof(Action<,,,>), typeof(Action<,,,,>), 
                                         typeof(Action<,,,,,>), typeof(Action<,,,,,,>), typeof(Action<,,,,,,,>), typeof(Action<,,,,,,,,>), typeof(Action<,,,,,,,,,>), 
                                         typeof(Action<,,,,,,,,,,>), typeof(Action<,,,,,,,,,,,>), typeof(Action<,,,,,,,,,,,,>), typeof(Action<,,,,,,,,,,,,,>), typeof(Action<,,,,,,,,,,,,,,>) };

        internal Callable(Delegate hisCb)
        {
            MethodInfo mi = hisCb.Method;
            ParameterInfo[] pi = mi.GetParameters();
            ptypes = pi.Select(p => p.ParameterType).ToArray();
            nParams = ptypes.Length;
            if (nParams > 0 && nParams < 17)
            {
                cb = Delegate.CreateDelegate(actions[nParams].MakeGenericType(ptypes), mi, false);
                if (cb == null)
                    Console.WriteLine("Warning: Unsuccessful attempt to CreateDelegate for " + hisCb + ", with methodinfo " + mi);
                else
                    Console.WriteLine("Successful attempt to CreateDelegate for " + hisCb + ", with methodinfo " + mi);
            }
            else
                cb = hisCb;
        }

        internal void doUpcall(object[] args)
        {
            if (args.Length != nParams)
                 throw new ArgumentException("Argument count must match number of parameters");
            switch (nParams)
            {
                case 1:
                    ((dynamic)cb).Invoke((dynamic)args[0]);
                    break;
                case 2:
                    ((dynamic)cb).Invoke((dynamic)args[0], (dynamic)args[1]);
                    break;
                    // ... cases 3-15 similar, omitted to save space
                default:
                    cb.DynamicInvoke((dynamic)args);
                    break;
            }
        }
    }

    internal class FooBar
    {
        internal FooBar()
        {
        }

        internal static void printFields(int i, string s)
        {
            Console.WriteLine("In FooBar.printField-s with i="+i+", s="+s);
        }

        internal void printFieldi(int i, string s)
        {
            Console.WriteLine("In FooBar.printField-i with i=" + i + ", s=" + s);
        }
    }

    internal class Program 
    { 
        private static void Main(string[] args) 
        {
            FooBar myFooBar = new FooBar();
            Callable cbfb0 = new Callable((myFoo)FooBar.printFields);
            cbfb0.doUpcall(new object[] { 77, "myfb" });
            Callable cbfb1 = new Callable((myFoo)myFooBar.printFieldi);
            cbfb1.doUpcall(new object[] { 77, "myfb" });
            string pc = "Main";
            Callable cb0 = new Callable((myNull)delegate() { Console.WriteLine("Hello from myNull"); });
            cb0.doUpcall(new object[0]);
            Callable cb1 = new Callable((myFoo)delegate(int i, string s) { Console.WriteLine("i=" + i + ", s.Length = " + s.Length); });
            Console.WriteLine("About to attempt to call Foo: Good args");
            cb1.doUpcall(new object[] { 2, "bar" });
            Console.WriteLine("After calling Foo");
            Callable cb2 = new Callable((myFoo)delegate(int i, string s) { Console.WriteLine("My parent class is " + pc + ", i=" + i + ", s.Length = " + s.Length); });
            Console.WriteLine("About to attempt to call Foo: Good args");
            cb2.doUpcall(new object[] { 12, "Bar" });
            Console.WriteLine("After calling Foo");
            System.Threading.Thread.Sleep(15000);
        } 

        private static void Foo(int i, string s) 
        { 
            Console.WriteLine("i=" + i + ", s.Length = " + s.Length); 
        } 
    } 
}

      

Can anyone help me understand why CreateDelegate behaves this way? The C # and .NET reference says it should work for both static and instance. If you break the "bad" case, you can confirm that the thing that determines success or failure is the value of the mi.isStatic icon.

PS: Note the use of (dynamic) to cast arguments to the required types at runtime! I think this is great. Used to be impossible - you want to do a cast (T), but don't know what type T will be and therefore can create an object of type T, but cannot make a dynamic method call using that object like in my 15 cases. By throwing on (dynamic) I avoid this problem - solves a problem for which there seem to be dozens of old threads left unresolved! (And this improves on the code suggested in the previous thread ... which had the same problem using known types).

+3


source to share


2 answers


CreateDelegate

creates the calling delegate - for this it must have an instance to invoke the method. Static methods do not require an instance - you call an overload that allows you to create a delegate for the static method.

To create a delegate on an instance method, you have to use a superclass, which also allows you to pass it in the following instance:



 cb = Delegate.CreateDelegate(actions[nParams].MakeGenericType(ptypes), 
                         hisCb.Target, 
                         mi, false);

      

+5


source


The only call I can see in Delegate.CreateDelegate

is the one that causes the overload that takes Type, MethodInfo, bool

. The documentation states that she

Creates a delegate of the specified type to represent the specified static method ...



If you have an instance method, you must call another overload (one that accepts object

) to create a delegate from it.

+1


source







All Articles