- 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/
我的问题:非常具体。我正在尝试想出解析以下文本的最简单方法: ^^domain=domain_value^^version=version_value^^account_type=account_ty
好吧,这就是我的困境: 我正在为 Reddit 子版 block 开发常见问题解答机器人。我在 bool 逻辑方面遇到了麻烦,需要一双更有经验的眼睛(这是我在 Python 中的第一次冒险)。现在,该
它首先遍历所有 y 值,然后遍历所有 x 值。我需要 X 和 y 同时改变。 For x = 3 To lr + 1 For y = 2 To lr anyl.Cells(x, 1)
假设我有一个包含 2 列的 Excel 表格:单元格 A1 到 A10 中的日期和 B1 到 B10 中的值。 我想对五月日期的所有值求和。我有3种可能性: {=SUM((MONTH(A1:A10)=
如何转换 Z-score来自 Z-distribution (standard normal distribution, Gaussian distribution)到 p-value ?我还没有找到
我正在重写一些 Javascript 代码以在 Excel VBA 中工作。由于在这个网站上搜索,我已经设法翻译了几乎所有的 Javascript 代码!但是,有些代码我无法准确理解它在做什么。这是一
我遇到过包含日期格式的时间戳日期的情况。然后我想构建一个图表,显示“点击”项目的数量“每天”, //array declaration $array1 = array("Date" => 0); $a
我是scala的新手! 我的问题是,是否有包含成员的案例类 myItem:Option[String] 当我构造类时,我需要将字符串内容包装在: Option("some string") 要么 So
我正在用 PHP 创建一个登录系统。我需要用户使用他或她的用户名或电子邮件或电话号码登录然后使用密码。因为我知道在 Java 中我们会像 email==user^ username == user 这
我在 C++ 项目上使用 sqlite,但是当我在具有文本值的列上使用 WHERE 时出现问题 我创建了一个 sqlite 数据库: CREATE TABLE User( id INTEGER
当构造函数是显式时,它不用于隐式转换。在给定的代码片段中,构造函数被标记为 explicit。那为什么在 foo obj1(10.25); 情况下它可以工作,而在 foo obj2=10.25; 情况
我知道这是一个主观问题,所以如果需要关闭它,我深表歉意,但我觉得它经常出现,让我想知道是否普遍偏爱一种形式而不是另一种形式。 显然,最好的答案是“重构代码,这样你就不需要测试是否存在错误”,但有时没有
这两个 jQuery 选择器有什么区别? 以下是来自 w3schools.com 的定义: [attribute~=value] 选择器选择带有特定属性,其值包含特定字符串。 [attribute*=
为什么我们需要CSS [attribute|=value] Selector根本当 CSS3 [attribute*=value] Selector基本上完成相同的事情,浏览器兼容性几乎相似?是否存在
我正在解决 regx 问题。我已经有一个像这样的 regx [0-9]*([.][0-9]{2})。这是 amont 格式验证。现在,通过此验证,我想包括不应提供 0 金额。比如 10 是有效的,但
我正在研究计算机科学 A 考试的样题,但无法弄清楚为什么以下问题的正确答案是正确的。 考虑以下方法。 public static void mystery(List nums) { for (
好的,我正在编写一个 Perl 程序,它有一个我收集的值的哈希值(完全在一个完全独立的程序中)并提供给这个 Perl 脚本。这个散列是 (string,string) 的散列。 我想通过 3 种方式对
我有一个表数据如下,来自不同的表。仅当第三列具有值“债务”并且第一列(日期)具有最大值时,我才想从第四列中获取最大值。最终值基于 MAX(DATE) 而不是 MAX(PRICE)。所以用简单的语言来说
我有一个奇怪的情况,只有错误状态保存到数据库中。当“状态”应该为 true 时,我的查询仍然执行 false。 我有具有此功能的 Controller public function change_a
我有一个交易表(针对所需列进行了简化): id client_id value 1 1 200 2 2 150 3 1
我是一名优秀的程序员,十分优秀!