将列表转换为我的类型的实例

时间:2016-01-09 11:54:43

标签: f#

我有类似的声明:

[<DataContract>] 
type Defect = 
    {
        [<field: DataMember(Name="referenceId")>]
        Referenceid  : string
        [<field: DataMember(Name="comment")>]
        Comment : string
        [<field: DataMember(Name="start")>]
        Start : DateTime
        [<field: DataMember(Name="finish")>]
        Finish : DateTime
    }

此类型有4个字段。我有4个元素的列表。 我有其他类型的n字段。我有n个元素的列表。

是否有通用的方法从列表中创建我的类型的实例,所以列表中的每个元素都将是该类型的对应字段?

2 个答案:

答案 0 :(得分:5)

您可以使用反射创建记录类型的实例。请考虑以下代码:

let make<'record> (values: obj []) = 
    let typ = typeof<'record>
    let fieldInfos = FSharpType.GetRecordFields(typ)

    let orderedValues = 
        // here you might need to reorder values using fieldInfos
        ...

    FSharpValue.MakeRecord(typ, values) :?> 'record 

唯一可能棘手的问题是以正确的顺序获取值,以便它们最终出现在正确的字段中。

我相信你想要的顺序是声明的顺序,但如果列表中的值标有字段名称,你可能想要实现那个排序逻辑,只是为了安全起见。

答案 1 :(得分:3)

除非你选择基于反射的编程,或者输入所有内容为obj,否则我很确定没有任何自动方式来做这样的事情。

考虑OP中的Defect类型。在结构上,它有两个string元素和两个DateTime元素。这与元组类型密切相关:

string * string * DateTime * DateTime

记录类型和元组之间的差异是:

  • 记录中有名为的元素;元组元素未命名。
  • 记录元素可以不按顺序引用;元组元素是有序的。

换句话说,即使元素的顺序与原始类型中的声明顺序不同,此表达式仍会编译为Defect值:

let d = {
    Finish = DateTime.Now
    Comment = "foo"
    Start = (DateTime 42L)
    Referenceid = "bar" }

您仍然可以按照定义命名元素的顺序写出记录值:

let d' = {
    Referenceid = "bar"    
    Comment = "foo"
    Start = (DateTime 42L)
    Finish = DateTime.Now }

在结构上,此值等同于此元组:

let t = ("bar", "foo", DateTime 42L, DateTime.Now)

到目前为止,应该清楚OP问题等同于常见问题How can I convert between list and tuple?

简短的回答是:你不能

这些类型结构不同。

给定Defect类型,等效列表的类型是什么?

它不能string list,因为它不可能包含DateTime值。它不能DateTime list,因为它可能包含string值。

通过定义一个被歧视的联盟来解决类型问题

type DefectElement = Text of string | Time of DateTime

let l = [Text "bar"; Text "foo"; Time (DateTime 42L); Time DateTime.Now]

现在l的类型为DefectElement list。但是,这并没有解决问题,因为它的不能保证按顺序包含正好四个元素

以下是DefectElement list类型的其他一些有效值:

[Text "bar"; Time (DateTime 42L); Text "foo"; Time DateTime.Now]
[Text "bar"; Time (DateTime 42L); Text "foo"; Time DateTime.Now; Text "baz"]
[Text "bar"; Time (DateTime 42L); Text "foo"]
[Text "bar"; Text "foo"; Text "foo"; Text "bar"]
List.empty<DefectElement>

您会注意到 none 中的 none 可以有意义地或明确地解释为与Defect对应的值。