gpt4 book ai didi

c# - 为什么 Func 与 Func> 不明确?

转载 作者:IT王子 更新时间:2023-10-29 04:38:11 24 4
gpt4 key购买 nike

这个让我感到困惑,所以我想我会在这里问,希望 C# 专家能向我解释。

为什么这段代码会产生错误?

class Program
{
static void Main(string[] args)
{
Foo(X); // the error is on this line
}

static String X() { return "Test"; }

static void Foo(Func<IEnumerable<String>> x) { }
static void Foo(Func<String> x) { }
}

有问题的错误:

Error
1
The call is ambiguous between the following methods or properties:
'ConsoleApplication1.Program.Foo(System.Func<System.Collections.Generic.IEnumerable<string>>)' and 'ConsoleApplication1.Program.Foo(System.Func<string>)'
C:\Users\mabster\AppData\Local\Temporary Projects\ConsoleApplication1\Program.cs
12
13
ConsoleApplication1

我使用什么类型并不重要——如果您在该代码中将“String”声明替​​换为“int”,您将得到相同类型的错误。这就像编译器无法区分 Func<T> 之间的区别。和 Func<IEnumerable<T>> .

有人可以阐明这一点吗?

最佳答案

好的,这就是交易。

简短版本:

  • 奇怪的是,歧义错误是正确的。
  • C# 4 编译器还会在正确的歧义错误之后产生虚假错误。这似乎是编译器中的错误。

长版:

我们有一个重载解析问题。过载解决方案非常明确。

第一步:确定候选集。这很容易。候选人是Foo(Func<IEnumerable<String>>)Foo(Func<String>) .

第二步:确定候选集中的哪些成员适用。适用成员的每个参数都可转换为每个参数类型。

Foo(Func<IEnumerable<String>>)适用的?嗯,是X可转换为 Func<IEnumerable<String>

我们引用规范的第 6.6 节。这部分规范就是我们语言设计者所说的“真奇怪”。基本上,它表示可以存在转换,但使用该转换是错误的。 (我们有这种奇怪情况的充分理由,主要是为了避免 future 的重大变化和避免“先有鸡还是先有蛋”的情况,但在您的情况下,我们会因此而遇到一些不幸的行为。)

基本上,这里的规则是,如果对 X() 形式的调用进行重载解析,则从 X 到不带参数的委托(delegate)类型的转换存在会成功。显然这样的调用成功,因此存在转换。实际上使用这种转换是错误的,因为返回类型不匹配,但是重载解析总是忽略返回类型

因此,存在来自 X 的转换至 Func<IEnumerable<String> ,因此该过载是一个适用的候选对象。

显然出于同样的原因,其他重载也是适用的候选对象。

第三步:我们现在有两个适用的候选人。哪个“更好”?

“更好”的是具有更具体类型的那个。如果您有两个适用的候选人,M(Animal)M(Giraffe)我们选择长颈鹿版本是因为长颈鹿比动物更具体。我们知道 Giraffe 更具体,因为每只 Giraffe 都是 Animal,但并非每只 Animal 都是 Giraffe。

但在您的情况下,这两种类型都不比另一种更具体。两种 Func 类型之间没有转换。

因此两者都不是更好,所以重载解析会报错。

然后 C# 4 编译器出现了一个看起来像是错误的东西,它的错误恢复模式无论如何都会选择一个候选者,并报告另一个错误。我不清楚为什么会这样。基本上是说错误恢复是选择 IEnumerable 重载,然后注意到方法组转换产生了无法维持的结果;即,该字符串与 IEnumerable<String> 不兼容.

整个情况相当不幸;如果返回类型不匹配,最好说没有方法组到委托(delegate)的转换。 (或者,产生错误的转换总是比不产生错误的转换更糟糕。)但是,我们现在坚持使用它。

一个有趣的事实:lambda 的转换规则确实考虑了返回类型。如果你说 Foo(()=>X())然后我们做正确的事。 lambda 和方法组具有不同的可转换规则这一事实相当不幸。

因此,总而言之,在这种情况下,编译器实际上是规范的正确实现,而这种特殊情况是一些可以说是不幸的规范选择的意外结果。

关于c# - 为什么 Func<T> 与 Func<IEnumerable<T>> 不明确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4573011/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com