我不认为我在做任何太深奥的事情,但我没有看到任何其他关于此的问题。
以下代码(我已将其简化为基本要素)在 C# 4 中生成编译器错误。但是,类型参数是什么应该是显而易见的 - 最大公分母(“A 类”)也是在方法“Frob”的返回类型中明确定义。编译器不应该列出 lambda 表达式中的所有返回类型,创建一个祖先树来找到它们的共同祖先,然后将其与包含方法的预期返回类型进行协调吗?
The type arguments for method 'System.Linq.Enumerable.Select(System.Collections.Generic.IEnumerable, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Sample
{
public abstract class A
{
private A(int index) { /* ... */ }
public sealed class A1 : A
{
public A1(string text, int index)
: base(index)
{ /* ... */ }
}
public sealed class A2 : A
{
public A2(int index)
: base(index)
{ /* ... */ }
}
private static Regex _regex = new Regex(@"(to be)|(not to be)");
public static IEnumerable<A> Frob(string frobbable)
{
return _regex.Matches(frobbable)
.Cast<Match>()
.Select((match, i) =>
{
if (match.Groups[1].Success)
{
return new A1(match.Groups[1].Value, i);
}
else
{
return new A2(i);
}
});
}
}
}
最佳答案
这是 C# 4 规范的第 7.5.2.12 节:
The inferred return type of an anonymous function F is used during type inference and overload resolution. The inferred return type can only be determined for an anonymous function where all parameter types are known, either because they are explicitly given, provided through an anonymous function conversion or inferred during type inference on an enclosing generic method invocation. The inferred return type is determined as follows:
- If the body of F is an expression, then the inferred return type of F is the type of that expression.
- If the body of F is a block and the set of expressions in the block’s return statements has a best common type T (§7.5.2.14), then the inferred return type of F is T.
- Otherwise, a return type cannot be inferred for E.
第 7.5.2.14 节是这样的:
In some cases, a common type needs to be inferred for a set of expressions. In particular, the element types of implicitly typed arrays and the return types of anonymous functions with block bodies are found in this way.
Intuitively, given a set of expressions E1…Em this inference should be equivalent to calling a method
Tr M<X>(X x1 … X xm)
with the Ei as arguments.
More precisely, the inference starts out with an unfixed type variable X. Output type inferences are then made from each Ei to X. Finally, X is fixed and, if successful, the resulting type S is the resulting best common type for the expressions. If no such S exists, the expressions have no best common type.
所以,假设我们有:
void M<X>(X x1, X x2) {}
A1 a1 = new A1();
A2 a2 = new A2();
M(a1, a2);
...这将无法确定 X
的类型参数,因此返回值推断以同样的方式失败。
我怀疑如果将返回值中的任一个转换为A
,它会起作用。
关于无法从具有多个返回的 Select 中的用法推断出 C# 类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11587536/