在这个问题的背景下被发现这个看似不一致的行为可以在F#2.0和F#3.0 RC中重现:
type Heterogeneous =
static member Echo([<ParamArray>] args: Object[]) = args
type Generic =
static member Echo<'T>([<ParamArray>] args: 'T[]) = args
Run Code Online (Sandbox Code Playgroud)
用法:返回:
Heterogeneous.Echo 0 // [|0|] OK
Generic.Echo 0 // [|0|] OK
Heterogeneous.Echo (0,1) // [|0; 1|] OK
Generic.Echo (0,1) // [|0; 1|] OK
Heterogeneous.Echo [|0|] // [|[|0|]|] OK?
Generic.Echo [|0|] // [|0|] OOPS!!
Heterogeneous.Echo ([|0|],[|1|])) // [|[|0|]; [|1|]|] OK
Generic.Echo ([|0|],[|1|])) // [|[|0|]; [|1|]|] OK
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释观察到的行为是否是一个错误或功能?
更新:
这个相关的答案传达了F#开发团队的一个确认,即现在在处理带ParamArray属性的泛型类型参数时存在错误.
这种情况有点令人困惑,因为当您使用数组作为标记的参数的实际参数时ParamArray,语言会尝试将其解释为将数组传递给正常的数组类型参数(因此ParamArray如果可能,它会忽略该属性).
在您的示例中,在第二种情况下可以这样做:
Generic.Echo [|0|]
Run Code Online (Sandbox Code Playgroud)
编译器推断出这'T是int因为你传递int[]给类型的参数,int[]所以编译器忽略ParamArray属性,方法只是得到一个包含的数组0.
在另一种情况下,这是不可能的:
Heterogeneous.Echo [|0|]
Run Code Online (Sandbox Code Playgroud)
该方法需要一个类型的参数obj[]和参数的类型int[],因此这两种类型不能统一(关键是编译器不会自动转换int[]为obj[]).由于这是不可能的,它会考虑该ParamArray属性并尝试转换int[]为obj并将其作为成员传递ParamArray- 这是编译器可以自动执行的转换,因此您可以获得所描述的结果.
如果你打电话Heterogeneous.Echo与obj[]作为参数,那么它会表现类似Generic.Echo.例如:
Heterogeneous.Echo [| box 0 |]
Run Code Online (Sandbox Code Playgroud)
如果您想了解详细信息,请参阅第14.4节.的F#语言规范.但是,重载决策规则非常复杂,所以我没有一个解释这种行为的确切参考 - 只是上面的非正式解释.