您可以在创建时不指定实例的情况下创建实例方法的委托吗?换句话说,你能创建一个“静态”委托,它的第一个参数是应该调用该方法的实例吗?
例如,如何使用反射构造以下委托?
Func<int, string> = i=>i.ToString();
我知道我可以使用 methodInfo.Invoke,但这比较慢,并且在调用它之前不会检查类型正确性。
当您拥有MethodInfo
特定静态方法的 时,可以使用 构造委托Delegate.CreateDelegate(delegateType, methodInfo)
,并且静态方法的所有参数保持自由。
正如 Jon Skeet 指出的那样,如果方法在引用类型上是非虚拟的,您可以简单地应用相同的方法来创建实例方法的开放委托。决定在虚拟方法上调用哪个方法是很棘手的,所以这不是那么简单,而且值类型看起来根本不起作用。
对于值类型,CreateDelegate
表现出非常奇怪的行为:
var func37 = (Func<CultureInfo,string>)(37.ToString);
var toStringMethod = typeof(int).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, new Type[] {typeof(CultureInfo) }, null);
var func42 = (Func<CultureInfo,string>)Delegate.CreateDelegate(typeof(Func<CultureInfo,string>), 42, toStringMethod,true);
Console.WriteLine( object.ReferenceEquals(func37.Method,func42.Method)); //true
Console.WriteLine(func37.Target);//37
Console.WriteLine(func42.Target);//42
Console.WriteLine(func37(CultureInfo.InvariantCulture));//37
Console.WriteLine(func42(CultureInfo.InvariantCulture));//-201040128... WTF?
如果实例方法属于值类型(这适用于引用类型),则作为目标对象调用CreateDelegate
with会引发绑定异常。null
几年后的一些跟进:func42(CultureInfo.InvariantCulture);
导致返回"-201040128"
而不是在我的示例中的错误绑定目标是"42"
可能允许远程代码执行的内存损坏(cve-2010-1898);这已在 2010 年的ms10-060安全更新中得到修复。当前框架正确打印 42!这并没有使回答这个问题变得更容易,但解释了示例中特别奇怪的行为。