当我尝试为实现接口的值类型方法创建开放实例委托时,Delegate.CreateDelegate失败。因为实例方法是基于值类型的,所以第一个参数必须是ref,因此让我们为此定义一个通用委托类型:
delegate T2 VF<T0, T1, T2>(ref T0 arg0, T1 arg1);
Run Code Online (Sandbox Code Playgroud)
现在,这是一个程序,该程序成功创建了一个到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"
}
}
Run Code Online (Sandbox Code Playgroud)
这似乎是由于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
Run Code Online (Sandbox Code Playgroud)
但这并不是我想要的,因为这似乎会将作为第一个参数传递的所有整数装箱。我也不想比较任何东西IEquatable<int>,我想专门调用比较两个int的方法。
对这里出什么问题有任何想法吗?
此处提到了一个Microsoft Connect错误,该错误似乎直接相关,但该链接对我而言不再有效,并且我无法通过搜索找到该错误。
编辑:请注意,尝试创建覆盖实例的打开实例委托时,会发生相同的问题,因此不只是接口方法。
小智 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("");
}
Run Code Online (Sandbox Code Playgroud)
编辑:刚刚注意到原始帖子的日期,但它仍然可以节省其他人很多时间。