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# リフレクションを使用することですが、(このような) リフレクションを単純に使用すると非常に遅くなる可能性があるため、実行しようとしている処理に対してパフォーマンスが十分かどうかを測定する必要があります (それが 1 つの場合)。 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 に答える