Delegate.CreateDelegate fails when I try to create open instance delegates to value type methods that implement interfaces. Because the instance method is on a value type, the first argument must be a ref, so let's define a general delegate type for this:
delegate T2 VF<T0, T1, T2>(ref T0 arg0, T1 arg1);
Now here's a program that succeeds in creating an open instance delegate to int.ToString(string), but fails to create an open instance delegate to int.Equals(int):
class Program
{
    static void Main(string[] args)
    {
        var tos = typeof(int).GetMethod("ToString", new[] { typeof(string) });
        var tosopen = Delegate.CreateDelegate(
                          typeof(VF<int, string, string>), null, tos);
        // success!
        var eq = typeof(int).GetMethod("Equals", new[] { typeof(int) });
        var eqopen = Delegate.CreateDelegate(
                         typeof(VF<int, int, bool>), null, eq);
        // previous line fails with "Error binding to target method"
    }
}
This seems to be due to the fact that int.Equals(int) implements IEquatable<int>. Note that  the following does work:
var x = typeof(IEquatable<int>).GetMethod("Equals", new Type[] { typeof(int) });
var xopen = Delegate.CreateDelegate(
                typeof(Func<IEquatable<int>, int, bool>), null, x);
xopen(1,1); // returns true
But this isn't exactly what I want, since this would seem to box any integers passed as the first argument. I also don't want to compare any IEquatable<int>, I want to specifically call the method to compare two ints.
Any thoughts on what's wrong here?
A Microsoft Connect bug was mentioned here that seems directly related, but that link no longer works for me, and I can't find that bug by searching.
Edit: note that the same problem occurs when trying to create open instance delegates to overridden methods, so it's not just interface methods.
This ran as part of a time test, hope it helps.
    public delegate Boolean RefFunc<T>(ref T arg1, Object arg2);
    static void Main(string[] args)
    {
        double loops = 1e6;
        Random random = new Random();
        System.Reflection.MethodInfo m;
        Stopwatch stopwatch = new Stopwatch();
        Type type = typeof(double);
        double tmp;
        stopwatch.Reset();
        stopwatch.Start();
        var deligates = new Dictionary<Type, RefFunc<double>>();
        RefFunc<double> d;
        for (int ii = 0; ii < loops; ii++)
        {
            if (!deligates.TryGetValue(type, out d))
            {
                m = type.GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(Object) }, null);
                d = (RefFunc<double>)Delegate.CreateDelegate(typeof(RefFunc<double>), null, m);
                deligates[typeof(double)] = d;
            }
            tmp = Convert.ToDouble(random.Next(0, 100));
            d(ref tmp, Convert.ToDouble(random.Next(0, 100)));
        }
        stopwatch.Stop();
        Console.WriteLine("Delegate " + stopwatch.Elapsed.ToString());
        Console.WriteLine("Delegate " + (stopwatch.Elapsed.Ticks / loops).ToString());
        Console.WriteLine("");
    }
Edit: Just noticed the original post's date, but it could still save others a lot of time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With