在 F# 中检索记录字段的值时获取可选类型的值
Get value of optional types when retrieving value of record fields in F#
我有一个定义如下的类型:
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 getFieldValueMappingOfARecordType (data: 'T) : seq<string * obj> =
let fieldValueMapping =
data.GetType()
|> FSharpType.GetRecordFields
|> Seq.map (
fun propertyInfo ->
(propertyInfo.Name, data |> propertyInfo.GetValue)
)
fieldValueMapping
然后用employee类型的实例调用上面的函数
let mapping = getFieldValueMappingOfARecordType emp
|> Seq.toList
给我们:
val mapping : (string * obj) list =
[("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
("Email", Some "E")]
到目前为止,它在非可选类型上运行良好。但在可选类型的情况下,它会将字段的值返回为 Some value
或 None
。我想做的是在字段有 Some value
时获取 value
或在字段为 None
时获取 null
。
基本上如下:
val mapping : (string * obj) list =
[("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
("Email", "E")]
或者如果员工实例如下所示:
let emp = {
Id = Guid "bc07e94c-b376-45a2-928b-508b888802c9"
Name = "A"
Phone = "B"
Email = None
}
然后,
val mapping : (string * obj) list =
[("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
("Email", null)]
这是我目前所拥有的(非工作代码):
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"
我认为唯一的方法就是反思:
let getSomeOrNull (t: Type) (o: obj) =
if isNull o then null
else t.GetProperty("Value").GetValue(o)
我认为这应该可以解决问题:
let getSomeOrNull (o: obj) =
match o with
| :? Option<string> as o -> a |> Option.toObj > box
| _ -> null
我有一个定义如下的类型:
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 getFieldValueMappingOfARecordType (data: 'T) : seq<string * obj> =
let fieldValueMapping =
data.GetType()
|> FSharpType.GetRecordFields
|> Seq.map (
fun propertyInfo ->
(propertyInfo.Name, data |> propertyInfo.GetValue)
)
fieldValueMapping
然后用employee类型的实例调用上面的函数
let mapping = getFieldValueMappingOfARecordType emp
|> Seq.toList
给我们:
val mapping : (string * obj) list =
[("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
("Email", Some "E")]
到目前为止,它在非可选类型上运行良好。但在可选类型的情况下,它会将字段的值返回为 Some value
或 None
。我想做的是在字段有 Some value
时获取 value
或在字段为 None
时获取 null
。
基本上如下:
val mapping : (string * obj) list =
[("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
("Email", "E")]
或者如果员工实例如下所示:
let emp = {
Id = Guid "bc07e94c-b376-45a2-928b-508b888802c9"
Name = "A"
Phone = "B"
Email = None
}
然后,
val mapping : (string * obj) list =
[("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
("Email", null)]
这是我目前所拥有的(非工作代码):
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"
我认为唯一的方法就是反思:
let getSomeOrNull (t: Type) (o: obj) =
if isNull o then null
else t.GetProperty("Value").GetValue(o)
我认为这应该可以解决问题:
let getSomeOrNull (o: obj) =
match o with
| :? Option<string> as o -> a |> Option.toObj > box
| _ -> null