【问题标题】:Type inference fails mysteriously类型推断神秘地失败了
【发布时间】:2012-06-05 00:07:55
【问题描述】:

为什么以下无法推断R

static R Foo<R>(Func<Action<R>, R> call) { ... }

虽然几乎“相同”,但有效:

static R Foo<R>(Func<Action, R> call) { ... }

用法:

var i = Foo(ec => -1);

“必须”调用第一个示例进行编译的方式:

var i = Foo<int>(ec => -1);

-- 或--

var i = Foo((Action<int> ec) => -1);

想法:从第二个 sn-p 中可以看出,R 已经由 'lambda' 的返回类型确定。为什么不能同样适用于第一个?即使使用ec(这应该是另一个编译器提示),它也无法推断。

【问题讨论】:

  • 因此,在您的示例中,ec 可转换为接受 int 并返回 void 的委托?
  • C# 中的类型推断规则是为了涵盖基本情况。在极少数情况下,规则(故意)不“接受”。
  • 您能添加一个ec 的示例声明/实现吗?我的猜测是问题出在那儿。
  • 这是一篇关于这个主题的有趣文章。 msdn.microsoft.com/en-us/vstudio/jj131514.aspx。可能会或可能不会真正回答您的问题,但有很好的背景信息。
  • 我可能找到了你的副本;)stackoverflow.com/questions/6229131/…

标签: c# generics type-inference


【解决方案1】:

我认为问题不在于编译器如果无法为函数R 推断出CallWithEscapeContinuation,而在于它无法推断出 lambda 的类型:

ec =>
{
  Enumerable.Range(0, 100).Select(x =>
  {
              // Called here, the compiler has no idea what signature to expect for `ec`
              // Could be Action<Int>, could be Action<Decimal> (for example).
    if (x == 40) ec(x);
    return x;
  }).ToList();
  return -1;
}

而当您提供​​ int 提示时,它可以从中推断出 lambda 的类型以及 CallWithEscapeContinuation 的签名。

当您只有 Action(而不是 Action&lt;R&gt;)时,上述内容无关紧要,因为没有影响 lambda 可能签名的类型参数。

【讨论】:

  • Range 返回IEnumerable&lt;int&gt;,为什么x 不是int
  • 如果您注释掉所有内容并仅返回 -1 它也不会推断返回类型。
  • 它也会失败:var index = CallWithEscapeContinuation(ec =&gt; { ec(1); return -1; });
  • @Slugart 那是因为它仍然不知道ec 是什么。
  • @ChrisShain:我不同意,它确切地知道ec 是什么。在这一点上它没有太多选择!