具有未知类型的CreateDelegate

我正在尝试创建Delegate用于在运行时读取/写入未知类型的类的属性。

我有一个generics类Main和一个如下所示的方法:

 Delegate.CreateDelegate(typeof(Func), get) 

其中get是应该读取的属性的MethodInfo 。 问题是当属性返回int (我猜这种情况发生在值类型中),上面的代码抛出了ArgumentException,因为该方法无法绑定。 在字符串的情况下,它运作良好。

为了解决这个问题,我更改了代码,以便使用MakeGenericType生成相应的Delegate类型。 所以现在的代码是:

 Type func = typeof(Func); Type generic = func.MakeGenericType(typeof(T), get.ReturnType); var result = Delegate.CreateDelegate(generic, get) 

现在的问题是创建的generic委托实例所以我必须使用DynamicInvoke ,这与使用纯reflection来读取字段一样慢。

所以我的问题是为什么第一段代码失败了值类型。 根据MSDN,它应该像它说的那样工作

如果方法的返回类型比委托的返回类型更具限制性,则委托的返回类型与方法的返回类型兼容

以及如何在第二个片段中执行委托,以便它比reflection更快。

谢谢。

这是解决问题的一种方法。 创建一个通用方法:

 public static Func MakeDelegate(MethodInfo @get) { var f = (Func)Delegate.CreateDelegate(typeof(Func), @get); return t => f(t); } 

这样,C#的编译器负责插入必要的装箱(如果有的话)以将f(t) (类型U )转换为object 。 现在你可以使用reflection来调用这个MakeDelegate方法,并将U设置为@get.ReturnType ,你得到的将是一个Func ,无需使用DynamicInvoke就可以调用它。

您的原始代码只适用于参考类型。 这就是字符串不是问题的原因,它直接来自System.Object。 值类型派生自ValueType和Object在纸上是一个很好的错觉,但实际上需要代码。 C#编译器会自动发出该代码,它需要一个装箱转换。 这是缺少的部分,没有BOX操作码 ,没有从int到对象的运行时转换。

您可以在代码中获取该操作码,但您必须使用System.Reflection.Emit。

在你去那里之前,首先检查你现在所拥有的是否真的太慢了​​。 reflection的代价是将元数据从组件中挖出。 这是在您创建委托时完成的,之后缓存了类型信息。

您调用失败,因为您需要对象而不是值类型(如INT) – 显然Func不是Func – 它不适用于任何vt,如double或bool。 要么返回一个盒装的Int(或者你得到的任何vt)。 或者(可能更好)使用reflection发射API。

通过使用reflection发射类您可以创建动态方法并将它们另存为委托,或创建动态委托并将其保存在某些结构中。 您只能执行一次(可能每个运行时一次)将其存储在某些Dict中并在需要时调用。

希望能帮助到你。 卢克

您是否可以将generics方法限制为仅使用引用类型,并创建另一个仅使用值类型,并决定相应使用哪些function?