22

当我遇到一个我不理解的类型推断错误时,我正在玩一个爱好项目。我已将其简化为以下简单示例。

我有以下类和功能:

class Foo { }
class Bar { }
class Baz { }

static T2 F<T1, T2>(Func<T1, T2> f) { return default(T2); }
static T3 G<T1, T2, T3>(Func<T1, Func<T2, T3>> f) { return default(T3); }

现在考虑以下示例:

// 1. F with explicit type arguments - Fine
F<Foo, Bar>(x => new Bar());

// 2. F with implicit type arguments - Also fine, compiler infers <Foo, Bar>
F((Foo x) => new Bar());

// 3. G with explicit type arguments - Still fine...
G<Foo, Bar, Baz>(x => y => new Baz());

// 4. G with implicit type arguments - Bang!
// Compiler error: Type arguments cannot be inferred from usage
G((Foo x) => (Bar y) => new Baz());

最后一个示例产生编译器错误,但在我看来,它应该能够毫无问题地推断类型参数。

问题:为什么编译器<Foo, Bar, Baz>在这种情况下不能推断?

更新:我发现简单地将第二个 lambda 包装在一个标识函数中会导致编译器正确推断所有类型:

static Func<T1, T2> I<T1, T2>(Func<T1, T2> f) { return f; }

// Infers G<Foo, Bar, Baz> and I<Bar, Baz>
G((Foo x) => I((Bar y) => new Baz()));

为什么它可以完美地完成所有单独的步骤,而不是一次完成整个推理?编译器分析隐式 lambda 类型和隐式泛型类型的顺序是否有一些微妙之处?

4

3 回答 3

19
于 2012-09-17T14:57:06.067 回答
1

无法推断 lambda 的返回类型是什么,因为它没有被分配并且无法由编译器确定。查看此链接,了解编译器如何确定 lambdas 返回类型。如果你有:

Func<Bar, Baz> f = (Bar y) => new Baz();
G((Foo x) => f);

那么编译器将能够根据分配给它的内容来计算 lambda 的返回类型,但是由于现在它没有分配给任何东西,编译器很难确定返回类型是什么(Bar y) => new Baz();

于 2012-09-04T06:07:02.287 回答
0

对于编译器,lambda 函数与 Func 不同,即对 Func 使用 lambda 函数意味着类型转换。专门化泛型时,编译器不会进行“嵌套”类型转换。但是,这在您的示例中是必需的:

的类型(Foo x) => (Bar y) => new Baz ()lambda (Foo, lambda (Bar, Baz)),但Func (T1, Func (T2, T3))需要,即两个转换,它们是嵌套的。

于 2012-09-04T07:46:37.670 回答