如何创建特定运行时类型的空列表

jbe*_*eko 6 f# list

给定.Net类型,比方说typeof<string>,在运行时如何创建等效的string list = []

我的动机是,当使用FSharpValue.MakeRecord基于解析的值创建记录时,需要将值作为a传递obj[].我一直在使用这些参数进行投射,box除了列表之外还有效.我遇到的问题是空的无类型列表列表不能装箱然后取消装箱.返回的具体错误是:

System.InvalidCastException: Unable to cast object of type 
'Microsoft.FSharp.Collections.FSharpList`1[System.Object]' 
to type 
'Microsoft.FSharp.Collections.FSharpList`1[System.String]'.
Run Code Online (Sandbox Code Playgroud)

一个空的类型列表可以装箱和取消装箱,所以我试图找到一种方法将列表转换为运行时类型,例如typeof <>返回的类型,但没有运气.

type Test = {Names : string list}
// fails
let genericList = []
{Names = unbox (box genericList)}

//works
let typedList : string list = []
{Names = unbox (box typedList)}

//works
let genericNonEmptyList = ["Bill"]
{Names = unbox (box genericNonEmptyList)}
Run Code Online (Sandbox Code Playgroud)

Tom*_*cek 5

让我再添加一个替代答案 - 尽管这两种现有方法都有效,但它们依赖于理解 F# 如何表示列表。在第一种情况下,您需要知道有Empty方法,在第二种情况下,您需要知道有一个名为 的联合案例Empty

我通常更喜欢通过定义辅助类型并使用自定义类型的反射来实现此目的:

type ListHelper =
  static member Empty<'T>() : list<'T> = []

let makeEmpty =
  let empty = typeof<ListHelper>.GetMethod("Empty")
  let emptyArr : obj[] = [| |]
  fun ty -> empty.MakeGenericMethod([| ty |]).Invoke(null, emptyArr)
Run Code Online (Sandbox Code Playgroud)

这为您提供了非常简单的函数,可以缓存MethodInfo(您甚至可以使用Expression预编译和缓存调用)并且不依赖于聪明的技巧。


s95*_*163 0

使用Seq.cast来转换空通用列表怎么样?

type Test = {Names : string list}
let genericList = []
let test = {Names = unbox (box genericList ) |> Seq.cast<string> |> Seq.toList}
test.Names //val it : string list = []
Run Code Online (Sandbox Code Playgroud)