- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个静态方法:
public class Example
{
//for demonstration purposes - just returns default(T)
public static T Foo<T>() { return default(T); }
}
我需要能够使用 Type
调用它参数调用可能很多,所以我的标准模式是创建一个线程安全的委托(delegate)缓存(在 .Net 4 中使用 ConcurrentDictionary
)动态调用 Foo<T>
方法与正确 T
.但是,如果没有缓存,代码是这样的:
static object LateFoo(Type t)
{
//creates the delegate and invokes it in one go
return (Func<object>)Delegate.CreateDelegate(
typeof(Func<object>),
typeof(Example).GetMethod("Foo", BindingFlags.Public | BindingFlags.Static).
MakeGenericMethod(t))();
}
这不是我第一次不得不这样做 - 过去我使用表达式树来构建和编译代理来调用目标方法 - 以确保从 int 返回类型转换和装箱 ->对象(例如)被正确处理。
更新 - 有效的表达式代码示例
static object LateFoo(Type t)
{
var method = typeof(Example)
.GetMethod("Foo", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(t);
//in practise I cache the delegate, invoking it freshly built or from the cache
return Expression.Lambda<Func<IField, object>>(Expression.Convert(
Expression.Call(method), typeof(object))).Compile()();
}
有点有趣的是,我很早就学会了使用显式 Convert
的表达式。是必需的并接受了它 - 代替这里的答案,现在可以理解为什么 .Net 框架不会自动将等价物插入。
结束更新
然而,这次我想我只需要使用 Delegate.CreateDelegate
因为它充分利用了以下事实(来自 MSDN):
Similarly, the return type of a delegate is compatible with the return type of a method if the return type of the method is more restrictive than the return type of the delegate, because this guarantees that the return value of the method can be cast safely to the return type of the delegate.
现在 - 如果我通过 typeof(string)
至 LateFoo
方法,一切正常。
但是,如果我通过 typeof(int)
我得到一个 ArgumentException
在 CreateDelegate
上电话、留言:Error binding to target method
.没有内部异常或进一步的信息。
所以看起来,为了方法绑定(bind)的目的,object
不被认为比 int
更具限制性.显然,这一定是因为装箱是一种不同于简单类型转换的操作,并且值类型不被视为与 object
协变。在 .Net 框架中;尽管在运行时存在实际类型关系。
C# 编译器似乎同意这一点(这是我可以模拟错误的最短方式,忽略代码会做什么):
public static int Foo()
{
Func<object> f = new Func<object>(Foo);
return 0;
}
不编译因为 Foo
方法“有错误的返回类型”-给定 CreateDelegate
问题,C# 只是在追随 .Net 的脚步。
在我看来,.Net 在处理协方差方面不一致 - 值类型要么是 object
或者不是; & 如果不是,则不应公开 object
作为基地(尽管它会让我们的生活变得更加困难)。因为它确实公开了 object
作为基础(或者它只是这样做的语言吗?),那么根据逻辑,值类型应该与 object
协变。 (或者你应该说的任何一种方式)使这个委托(delegate)正确绑定(bind)。如果协方差只能通过装箱操作来实现;那么框架应该处理这个问题。
我敢说这里的答案是 CreateDelegate 并没有说它将以协变方式处理框操作,因为它只使用“cast”这个词。我还希望有关于值(value)类型和对象协变等更广泛主题的完整论文,我正在大声疾呼一个早已不复存在且已解决的主题。不过,我认为有一些我不明白或错过的东西 - 所以请指教!
如果无法回答 - 我很乐意删除。
最佳答案
如果参数和返回值可以使用表示保留转换来转换,则只能以这种方式转换委托(delegate)。
一些相关的博客文章:
This dichotomy motivates yet another classification scheme for conversions (†). We can divide conversions into representation-preserving conversions (B to D) and representation-changing conversions (T to U). (‡) We can think of representation-preserving conversions on reference types as those conversions which preserve the identity of the object. When you cast a B to a D, you’re not doing anything to the existing object; you’re merely verifying that it is actually the type you say it is, and moving on. The identity of the object and the bits which represent the reference stay the same. But when you cast an int to a double, the resulting bits are very different.
This is why covariant and contravariant conversions of interface and delegate types require that all varying type arguments be of reference types. To ensure that a variant reference conversion is always identity-preserving, all of the conversions involving type arguments must also be identity-preserving. The easiest way to ensure that all the non-trivial conversions on type arguments are identity-preserving is to restrict them to be reference conversions. http://blogs.msdn.com/b/ericlippert/archive/2009/03/19/representation-and-identity.aspx
"but how can a value type, like int, which is 32 bits of memory, no more, no less, possibly inherit from object? An object laid out in memory is way bigger than 32 bits; it's got a sync block and a virtual function table and all kinds of stuff in there." Apparently lots of people think that inheritance has something to do with how a value is laid out in memory. But how a value is laid out in memory is an implementation detail, not a contractual obligation of the inheritance relationship! When we say that int inherits from object, what we mean is that if object has a member -- say, ToString -- then int has that member as well. http://ericlippert.com/2011/09/19/inheritance-and-representation/
关于c# - Delegate.CreateDelegate 不会将返回值装箱 - 是故意的,还是疏忽?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8818089/
我正在尝试创建委托(delegate)以在运行时读取/写入未知类型类的属性。 我有一个通用类 Main和一个看起来像这样的方法: Delegate.CreateDelegate(typeof(Func
这是 prior thread 的一种后续。我正在构建一个小型包装器来向上调用我的用户提供的动态类型化方法。该方案运作良好......但仅适用于静态方法。尽管 CreateDelegate 也应该适用
感谢 Jon Skeet 在 this 中的回答问题我有以下工作: public delegate BaseItem GetItemDelegate(Guid itemID); public stat
假设我想传递一个成员函数作为回调。 我应该使用什么来传递上下文 - bind() 或 createDelegate()? 我的意思是,这个: someObj.on('someEvent', this.
我有以下问题:我想调用 Delegate.CreateDelegate从我针对 .NET 4.5、Windows Phone 8 和 Windows 8 商店应用程序的可移植类库中,但我的代码无法编译
我一直在尝试使用反射来比较在编译时类型未知的对象,而不是每次尝试使用 CreateDelegate() 时都调用 Invoke()。到目前为止,我已经在基本类型等的通用类型类中使用它,但我遇到了类型为
这是我第一次尝试将用户定义的参数传递给 IE9 中 extjs(4.0.1) 中的处理程序函数。我有以下代码,但它抛出了一个错误,指出 SCRIPT438: Object doesn't suppor
这是我第一次尝试将用户定义的参数传递给 IE9 中 extjs(4.0.1) 中的处理程序函数。我有以下代码,但它抛出了一个错误,指出 SCRIPT438: Object doesn't suppor
使用 Jon Skeet 的文章 Making reflection fly and exploring delegates作为指南,我正在尝试使用 Delegate.CreateDelegate 方
在创建接口(interface)方法的委托(delegate)时,我正在努力寻找哪里出错了 我的代码如下: private static Func> FindScrapeMethod(ICrawler
编辑:我在 microsoft connect::上提交了错误报告: https://connect.microsoft.com/VisualStudio/feedback/details/61423
现在,我必须这样做 private delegate void set(int obj); //declare the prototype ... Delegate delegate1 = Deleg
我尝试为 this question 实现 Jon Skeet 的解决方案发布在此 blog post将 SetValue 方法替换为使用委托(delegate)的非反射方法。 与blog post中
我正在尝试使用 Delegate.CreateDelegate [MSDN link]绑定(bind)到静态泛型方法,但绑定(bind)失败。这是 PoC 代码: public static clas
我在看的实现 Observable.FromEvent(add, remove) 我正在努力了解它是如何工作的。让我们说 TEventHandler 是标准: public delegate void
我有一个静态方法: public class Example { //for demonstration purposes - just returns default(T) publ
关于Making reflection fly and exploring delegates的问题... 如果我需要创建委托(delegate) Func我可能会使用的动态加载类型的方法 (1) D
当我调用 CreateDelegate(delegateType) 时,我得到一个 System.ArgumentException,根据 MSDN,这是因为 delegateType 的参数数量错误
在遵循这个问题的答案后,我发现我必须使用 ref 参数来调用结构上的实例方法。 How can I create an open Delegate from a struct's instance m
运行 Run2 方法。但是Run方法没有运行。是什么原因 ?两种方法之间的唯一区别是因为参数。 public class MyClass { public string Name { get;
我是一名优秀的程序员,十分优秀!