仅当S和T不同时,才从λ表达式的输出推断出Func <S,T>的T?

naw*_*fal 9 c# generics type-inference func

ST不同时,这有效:

public static void Fun<S, T>(Func<S, T> func)
{

}

Fun((string s) => true); //compiles, T is inferred from return type.
Run Code Online (Sandbox Code Playgroud)

但,

public static void Fun<T>(Func<T, T> func)
{

}

Fun(t => true); //can't infer type.
Run Code Online (Sandbox Code Playgroud)

在第一个例子中,既然T是从lambda表达式的返回类型推断出来的,那么T在第二个例子中也不能推断出来?我想它这样做,但为什么第一次T不知道,如果将第二TFunc<T, T>是已知的,毕竟T == T对不对?或者在Funcs的情况下是否有推断类型的订单?

Eri*_*ert 13

它与S和T不同,没有任何关系.它与您在第一种情况下提供形式参数类型而在第二种情况下不提供它有关.

方法类型推断不会尝试从lambda推断委托的返回类型,直到知道委托的形式参数类型为止.

在第二种情况下,你没有给编译器任何推断形式参数类型T的东西,因此甚至不会分析lambda的主体.

"形式参数类型"是什么意思?

形式参数是一个变量,它接受传递给方法,索引器,构造函数,lambda或匿名方法的参数的值.(或者,在outref参数形式的情况下,成为调用者提供的变量的别名.)形式参数是变量,因此具有类型.

委托delegate R Func<A, R>(A a);具有a类型的形式参数A.您可以使用方法类型参数构造它Func<S, T>,因此委托的形式参数类型现在是S.类型推断的任务是推断那些类型ST.

在你的第一个例子中,你有一个带有形式参数s类型的lambda string.所以类型推断的原因是因为这拉姆达参数对应于形参func的方法Fun,并正式参数类型funcFunc<S, T>那么正式的参数类型s必须对应S.由于您给出了正式的参数类型s,S因此推断为string.

一旦做出推断,则T可以通过分析lambda的主体来推断.

在第二种情况下,没有给出正式的参数类型t.由于没有其他任何类型t可以推导出来,因此类型推断会放弃并放弃在查看正文之前分析这个lambda.

恰好在你的情况下,可以独立于lambda的形式参数类型来分析主体.这是一种罕见的情况,并且没有编写类型推断算法来利用它.

如果这是您想要的类型推断,请考虑使用F#而不是C#.它具有更先进的类型推断算法,基于Hindley-Milner算法.

  • @Jodrell:HM规则的符号看起来很可怕,直到你学会阅读所有希腊语,然后它变得非常简单.例如,`Γ⊢e:τ→σΓ⊢f:τ/Γ⊢ef:σ`仅仅意味着"如果你有证据证明'e`是从'T`到`S`的函数,你有证据那个`f`是一个'T`类型的表达式,那么你就有足够的证据来推断出表达式'e(f)`将是'S`类型.这个符号与写出来相比非常简洁英语,但它真的没有表达任何非常复杂的东西. (3认同)

Jef*_*ado 5

lambdas和其他函数的通用参数由它们的参数类型决定,而不是它们的返回类型.这与你不能这样做的原因完全相同:

T Foo<T>() { return default(T); }

string x = Foo(); // error
Run Code Online (Sandbox Code Playgroud)

对于表达式t => true,我们显然不知道t可能是什么,因此编译器不能仅基于此做出任何更多的决策.