5

当我尝试为实现接口的值类型方法创建开放实例委托时,Delegate.CreateDelegate 失败。因为实例方法是值类型,所以第一个参数必须是 ref,所以让我们为此定义一个通用委托类型:

delegate T2 VF<T0, T1, T2>(ref T0 arg0, T1 arg1);

现在这是一个程序,它成功地为 int.ToString(string) 创建了一个开放实例委托,但未能为 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"
    }
}

这似乎是由于 int.Equals(int) 实现的事实IEquatable<int>。请注意,以下操作确实有效:

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

但这并不是我想要的,因为这似乎将作为第一个参数传递的任何整数装箱。我也不想比较任何IEquatable<int>,我想专门调用方法来比较两个整数。

对这里有什么问题有任何想法吗?

这里提到了一个似乎直接相关的 Microsoft Connect 错误,但该链接不再适用于我,而且我无法通过搜索找到该错误。

编辑:请注意,在尝试为覆盖方法创建开放实例委托时会出现同样的问题,因此它不仅仅是接口方法。

4

1 回答 1

1

这是作为时间测试的一部分运行的,希望对您有所帮助。

    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("");
    }

编辑:刚刚注意到原始帖子的日期,但它仍然可以为其他人节省很多时间。

于 2016-03-03T03:11:56.817 回答