我有一个简单的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,反之亦然?如果没有这样的功能,怎么能以简洁的方式完成呢?
答案 0 :(得分:9)
没有内置功能。</ p>
实现转换的最直接方法是使用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 ]