简体   繁体   English

检索 F# 中记录字段的值时获取可选类型的值

[英]Get value of optional types when retrieving value of record fields in F#

I have a type defined as follows:我有一个类型定义如下:

type Employee = {
    Id:    Guid
    Name:  string
    Phone: string
    Email: Option<string>
}

and an instance of this type:和这种类型的一个实例:

let emp = {
    Id = Guid "bc07e94c-b376-45a2-928b-508b888802c9"
    Name = "A"
    Phone = "B"
    Email = Some "E"
}

I want to extract the field names and values from this record type using reflection like the following:我想使用反射从该记录类型中提取字段名称和值,如下所示:

let getFieldValueMappingOfARecordType (data: 'T) : seq<string * obj> =
    let fieldValueMapping =
        data.GetType()
        |> FSharpType.GetRecordFields
        |> Seq.map (
            fun propertyInfo ->

                    (propertyInfo.Name, data |> propertyInfo.GetValue)
        )
    fieldValueMapping

Then invoking the above function with the instance of employee type然后用员工类型的实例调用上面的 function

let mapping = getFieldValueMappingOfARecordType emp
            |> Seq.toList

gives us:给我们:

val mapping : (string * obj) list =
  [("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
   ("Email", Some "E")]

So far it's working well with non-optional type.到目前为止,它适用于非可选类型。 But in case of optional types, it's returning the value of the field as either Some value or None .但在可选类型的情况下,它将字段的值作为Some valueNone返回。 What I would like to do is to get the value when the field has Some value or make it null when it's None .我想做的是在字段具有Some value时获取该value ,或者在为None时将其null

Essentially like the follwing:基本上像下面这样:

val mapping : (string * obj) list =
  [("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
   ("Email", "E")]

Or if the employee instance is like the following:或者,如果员工实例如下所示:

let emp = {
    Id = Guid "bc07e94c-b376-45a2-928b-508b888802c9"
    Name = "A"
    Phone = "B"
    Email = None
}

Then,然后,

val mapping : (string * obj) list =
  [("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
   ("Email", null)]

This is what I have so far (non-working code):这是我到目前为止所拥有的(非工作代码):

open System
open Microsoft.FSharp.Reflection
open System.Reflection

type Employee = {
    Id:    Guid
    Name:  string
    Phone: string
    Email: Option<string>
}

let emp = {
    Id = Guid "bc07e94c-b376-45a2-928b-508b888802c9"
    Name = "A"
    Phone = "B"
    Email = Some "E"
}

let getSomeOrNull (t: Type) (o: obj) =
    let opt = typedefof<option<_>>.MakeGenericType [| t |]
    match (o :?> opt) with
    | Some s ->
        s
    | None ->
        null

let getValues (data: 'T) =
    let values =
        data.GetType()
        |> FSharpType.GetRecordFields
        |> Array.map (
            fun propertyInfo ->
                let value =
                    data |> propertyInfo.GetValue

                let isOption =
                    propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() = typedefof<Option<_>>

                match isOption with
                | true ->
                    (propertyInfo.Name, (getSomeOrNull propertyInfo.PropertyType value))
                | false ->
                    (propertyInfo.Name, value)
        )
    values

getValues emp
|> printfn "%A"

I think the only way to do this is with reflection:我认为做到这一点的唯一方法是反思:

let getSomeOrNull (t: Type) (o: obj) =
    if isNull o then null
    else t.GetProperty("Value").GetValue(o)

I think this should do the trick:我认为这应该可以解决问题:

let getSomeOrNull (o: obj) =
    match o with
    | :? Option<string> as o -> a |> Option.toObj > box
    | _ -> null

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM