【发布时间】:2020-11-07 16:40:52
【问题描述】:
我有一个 F# 记录类型
type MyType = {
Name : string
Description : string option
}
我想要两个数组,一个包含必需属性的名称,一个包含可选属性。我该怎么做?
【问题讨论】:
标签: .net reflection properties f# record
我有一个 F# 记录类型
type MyType = {
Name : string
Description : string option
}
我想要两个数组,一个包含必需属性的名称,一个包含可选属性。我该怎么做?
【问题讨论】:
标签: .net reflection properties f# record
open System.Reflection
/// inspired by https://stackoverflow.com/questions/20696262/reflection-to-find-out-if-property-is-of-option-type
let isOption (p : PropertyInfo) =
p.PropertyType.IsGenericType &&
p.PropertyType.GetGenericTypeDefinition() = typedefof<Option<_>>
/// required and optional property names of a type 'T - in that order
/// inspired by https://stackoverflow.com/questions/14221233/in-f-how-to-pass-a-type-name-as-a-function-parameter
/// inspired by https://stackoverflow.com/questions/59421595/is-there-a-way-to-get-record-fields-by-string-in-f
let requiredAndOptionalPropertiesOf<'T> =
let optionals, requireds = typeof<'T>.GetProperties() |> Array.partition isOption
let getNames (properties : PropertyInfo[]) = properties |> Array.map (fun f -> f.Name)
(getNames requireds, getNames optionals)
【讨论】:
FSharpType.GetRecordFields typeof<MyType>,所以如果规范发生变化,它不会破坏任何东西。
FSharp.Reflection.FSharpType.GetRecordFields 比 typeof<'T>.GetProperties() 更安全吗?
GetRecordFields 是 API 表面的一部分,即使属性映射到记录字段的内部实现发生变化,API 行为也将保持不变。话虽如此,如果 T 不是记录类型,GetRecordFields 将抛出,并且仅返回具有字段映射的属性(即,CompilationMappingAttribute 已应用),并尊重声明的顺序。
这是考虑到@Asti 评论的替代答案:
open System.Reflection
let isOption (p : PropertyInfo) =
p.PropertyType.IsGenericType &&
p.PropertyType.GetGenericTypeDefinition() = typedefof<Option<_>>
let requiredAndOptionalPropertiesOf<'T> =
let optionals, requireds = FSharp.Reflection.FSharpType.GetRecordFields typeof<'T> |> Array.partition isOption
let getNames (properties : PropertyInfo[]) = properties |> Array.map (fun f -> f.Name)
(getNames requireds, getNames optionals)
【讨论】: