我认为F#函数和System.Func之间的转换必须手动完成,但似乎有一种情况,编译器(有时)会为你做.当出错时,错误信息不准确:
module Foo =
let dict = new System.Collections.Generic.Dictionary<string, System.Func<obj,obj>>()
let f (x:obj) = x
do
// Question 1: why does this compile without explicit type conversion?
dict.["foo"] <- fun (x:obj) -> x
// Question 2: given that the above line compiles, why does this fail?
dict.["bar"] <- f
Run Code Online (Sandbox Code Playgroud)
最后一行无法编译,错误是:
This expression was expected to have type
System.Func<obj,obj>
but here has type
'a -> obj
Run Code Online (Sandbox Code Playgroud)
显然,该功能f
没有签名'a > obj
.如果F#3.1编译器对第一个字典赋值感到满意,那为什么不是第二个呢?
应该解释这一点的规范的一部分是8.13.7在成员调用中的类型定向转换.简而言之,在调用成员时,将应用从F#函数到委托的自动转换.不幸的是,规范有点不清楚; 从措辞看来,这种转换可能适用于任何函数表达式,但实际上它似乎只适用于匿名函数表达式.
规格也有点过时了; 在F#3.0类型定向转换中也可以转换为System.Linq.Expressions.Expression<SomeDelegateType>
.
编辑
在查看过去与F#团队的一些通信时,我想我已经跟踪了转换如何应用于非语法函数表达式.为了完整起见,我将它包括在这里,但这是一个奇怪的角落情况,因此对于大多数目的,您应该考虑规则是只有语法函数将应用类型定向转换.
例外是重载解析可能导致转换函数类型的任意表达式; 第14.4节方法应用解决方案部分解释了这一点,尽管它非常密集且仍然不完全清楚.基本上,只有在存在多个重载时才会详细说明参数表达式; 当只有一个候选方法时,参数类型会根据无法解释的参数进行断言(注意:根据转换是否适用,这实际上并不重要,但它在经验上确实很重要).这是一个演示此异常的示例:
type T =
static member M(i:int) = "first overload"
static member M(f:System.Func<int,int>) = "second overload"
let f i = i + 1
T.M f |> printfn "%s"
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
208 次 |
最近记录: |