4

我有以下类型的简单 F# 记录数组(或依赖于系统类型的一些小变化):

type Transaction= {
    date: DateTime;
    amount: float;
    mutable details: string }

我想将它们显示到 Winforms 中的 DataGridView 控件,包括支持更改内容以及添加或删除行/记录。将 DataViewGrid 绑定到记录数组似乎不允许添加/删除行(或者我一定做错了吗?)。然而,DataTable 结构似乎更适合此目的。创建上述类型的 DataTable 似乎与原始记录类型非常匹配,例如:

let dataTable = new DataTable()
    dataTable.Columns.Add("date", typeof<DateTime>) |> ignore
    dataTable.Columns.Add("amount", typeof<float>) |> ignore
    dataTable.Columns.Add("details", typeof<string>) |> ignore)

所以我想知道是否有一个现有的系统函数可以将依赖于系统类型的任何类型的记录的记录数组(例如,类型“事务数组”)转换为相应的DataTable,反之亦然?如果没有这样的功能,如何以简洁的方式完成?

4

1 回答 1

8

没有内置功能。

实现转换的最直接方法是使用 F# 反射,但天真的使用反射(像这样)可能会很慢,因此您应该衡量性能是否足以满足您的要求(如果它是一个关闭转换以在 UI 中显示内容,这可能很好)。

这是您如何做到这一点的草图:

open Microsoft.FSharp.Reflection

let recordsToDataTable (items:'T list) =
  // Create data table and add fields based on the record type
  let dataTable = new DataTable() 
  let fields = FSharpType.GetRecordFields(typeof<'T>)
  for fld in fields do
    dataTable.Columns.Add(fld.Name, fld.PropertyType) |> ignore
  // Add values from the specified list to the table
  for itm in items do
    let row = dataTable.NewRow()
    // Set all fields of the current row
    for fld in fields do
      row.[fld.Name] <- fld.GetValue(itm)
    dataTable.Rows.Add(row)
  dataTable      

let dataTableToRecords (table:DataTable) : 'T list =
  let fields = FSharpType.GetRecordFields(typeof<'T>)
  // Create a list with item for every row in the table
  [ for row in table.Rows ->
      // Get values of all fields from DT and create a record value
      let values = [| for fld in fields -> row.[fld.Name] |]
      FSharpValue.MakeRecord(typeof<'T>, values) :?> 'T ]
于 2012-10-05T12:16:50.600 回答