您有很多问题。 (将来我建议当您有多个问题时,将它们分成多个问题,而不是在一张帖子中包含多个问题;您可能会得到更好的答复。)
为什么编译器无法推断出以下中的“int”类型参数:
TryParseExtensions.OrNull(int.TryParse, "2");
好问题。我不在这里回答这个问题,而是向您推荐我 2007 年的文章,其中解释了为什么这在 C# 3.0 中不起作用:
http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx
总结:从根本上来说,这里存在一个先有鸡还是先有蛋的问题。我们必须对 int.TryParse 进行重载解析,以确定 TryParse 的哪个重载是预期的重载(或者,如果它们都不起作用,则错误是什么。)重载解析总是尝试从论点。但在这种情况下,这正是我们试图推断的论证类型。
我们可以提出一种新的重载解析算法,它说“好吧,如果方法组中只有一个方法,那么即使我们不知道参数是什么,也选择那个方法”,但这似乎很弱。对于只有一个方法的特殊情况方法组来说,这似乎是一个坏主意,因为这会因为添加新的重载而受到惩罚;它可能突然成为一个重大变化。
正如您从该文章的评论中看到的,我们收到了很多很好的反馈。得到的最好的反馈基本上是“好吧,假设类型推断有already计算出所有参数的类型,它是返回类型我们正在尝试推断;在这种情况下,您可以进行重载解析”。该分析是正确的,并且对该效果的更改进入了 C# 4。我在这里详细讨论了这一点:
http://blogs.msdn.com/b/ericlippert/archive/2008/05/28/method-type-inference-changes-part-zero.aspx http://blogs.msdn.com/b/ericlippert/archive/2008/05/28/method-type-inference-changes-part-zero.aspx
我是否正确理解扩展方法不会在委托类型上被发现,因为我猜它们并不是真正的那种类型(而是一个“方法”),只是恰好与委托签名匹配?
你的术语有点偏离,但你的想法是正确的。当“接收者”是一个时,我们不会发现扩展方法方法组。更一般地说,当接收者缺乏自己的类型时,我们不会发现扩展方法,而是根据其上下文采用类型:方法组、lambda、匿名方法和 null 文字都具有此属性。说起来真的很奇怪null.Whatever()
并让其调用 String 上的扩展方法,甚至更奇怪,(x=>x+1).Whatever()
并让其调用扩展方法Func<int, int>
.
描述此行为的规范行是:
从[接收者表达式]到第一个参数的类型[...]的隐式标识、引用或装箱转换[必须存在]。
方法组上的转换不是恒等、引用或装箱转换;它们是方法组转换。
场景 1 是否可行(当然不是具体的场景,而是一般情况)?我想从语言/编译器的角度来看,它实际上有用,还是我只是(试图)在这里疯狂地滥用东西?
它不是不可行的。我们这里有一支非常聪明的团队,但没有理论的不可能这样做的原因。在我们看来,它并不是一个为语言增加更多价值的功能,而不是额外的复杂性成本。
有时它会很有用。例如,我希望能够做到这一点;假设我有一个static Func<A, R> Memoize<A, R>(this Func<A, R> f) {...}
:
var fib = (n=>n<2?1:fib(n-1)+fib(n-2)).Memoize();
而不是你今天必须写的内容是:
Func<int, int> fib = null;
fib = n=>n<2?1:fib(n-1)+fib(n-2);
fib = fib.Memoize();
但坦率地说,所提议的功能给语言增加的额外复杂性并没有因为使上面的代码变得不那么冗长而带来的小小的好处而得到补偿。