F#中的数组协方差

时间:2011-09-07 18:52:40

标签: .net arrays f# covariance

由于.NET数组是协变的,因此以下适用于C#:

var strArray = new string[0];
object[] objArray = strArray;

在F#中,给定一个数组'T[],将其转换为obj[]的最佳方式是什么,而无需重新创建数组(例如Array.map box)?我正在使用(box >> unbox),但感觉很草率。

3 个答案:

答案 0 :(得分:5)

正如Brian所说,box >> unbox没有任何问题,除此之外,数组协方差本身就被破坏了(例如([| "test" |] |> box |> unbox<obj[]>).[0] <- obj()会在尝试执行赋值时抛出ArrayTypeMismatchException。)

相反,您可能最好将string[]视为obj seq,这是非常安全的(尽管它仍然需要F#中的装箱和拆箱,因为F#不支持通用协同-方差)。不幸的是,如果你走这条路,你会失去随机访问。

答案 1 :(得分:4)

box >> unbox

似乎是一个好主意; O(1),并且显然完成了工作。

还要考虑不使用此CLR错误功能。 ;)

答案 2 :(得分:3)

Brian的解决方案对我来说很好,但你真的需要数组协方差吗?

如果你的函数需要ISomething[]并想要传递它SomeSomething[]那么你需要它,但是如果函数只从数组中读取类型ISomething的值(这是协方差允许的是什么),然后你可以使用hash-type并编写一个带#ISomething[]的函数。 (当然,假设你可以修改这个功能!)

这样,该函数可以处理实现ISomething的任何元素的数组,并且在调用它时不需要数组协方差。这是一个例子:

type A() = 
  interface IDisposable with 
    member x.Dispose() = printfn "gone"

// Disposes the first element from an array
let disposeFirst (a:#IDisposable[]) = a.[0].Dispose()

// Call 'disposeFirst' with 'A[]' as an argument
let aa = [| new A(); new A() |]
disposeFirst aa

在我看来,.NET中数组协方差的主要原因是当泛型不存在时需要它,但似乎F#可以没有这个功能就好了。