【问题标题】:Convert list to instance of my type将列表转换为我的类型的实例
【发布时间】:2016-01-09 11:54:43
【问题描述】:

我有这样声明的类型:

[<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 元素的列表。

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

【问题讨论】:

  • 从您的列表中创建一个 json 字符串,然后将该字符串 json-serialize 到您的对象(使用 JSON.net)?
  • 在这种情况下,我需要为我的每种类型编写 List2JSON 函数吗?换句话说 - 我是否需要拥有与我拥有的类型一样多的 list2json 函数?
  • 您只需要一个 List2Json 函数,其类型为 list -&gt; string,其中输出是您的 json 字符串,然后使用名为 Newtonsoft.JSON 的包,您可以使用一个函数来反序列化该字符串,如下所示:@ 987654326@

标签: f#


【解决方案1】:

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

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 

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

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

【讨论】:

    【解决方案2】:

    除非您选择基于反射的编程,或者将所有内容都输入为obj,否则我很确定没有任何自动方法可以做到这一点。

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

    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 可以有意义地或明确地解释为对应于Defect 的值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-10
      • 2021-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多