我想获得Enum.GetName
F# 歧视工会成员的等价物。调用ToString()
给了我 TypeName+MemberName,这不是我想要的。当然,我可以对它进行子串化,但它安全吗?或者也许有更好的方法?
问问题
2991 次
4 回答
33
您需要使用Microsoft.FSharp.Reflection
命名空间中的类,以便:
open Microsoft.FSharp.Reflection
///Returns the case name of the object with union type 'ty.
let GetUnionCaseName (x:'a) =
match FSharpValue.GetUnionFields(x, typeof<'a>) with
| case, _ -> case.Name
///Returns the case names of union type 'ty.
let GetUnionCaseNames <'ty> () =
FSharpType.GetUnionCases(typeof<'ty>) |> Array.map (fun info -> info.Name)
// Example
type Beverage =
| Coffee
| Tea
let t = Tea
> val t : Beverage = Tea
GetUnionCaseName(t)
> val it : string = "Tea"
GetUnionCaseNames<Beverage>()
> val it : string array = [|"Coffee"; "Tea"|]
于 2009-08-11T10:17:23.100 回答
2
@DanielAsher 的回答有效,但为了让它更优雅(而且速度更快?因为其中一种方法缺乏反射),我会这样做:
type Beverage =
| Coffee
| Tea
static member ToStrings() =
Microsoft.FSharp.Reflection.FSharpType.GetUnionCases(typeof<Beverage>)
|> Array.map (fun info -> info.Name)
override self.ToString() =
sprintf "%A" self
于 2016-12-17T14:21:58.153 回答
1
我想提出更简洁的建议:
open Microsoft.FSharp.Reflection
type Coffee = { Country: string; Intensity: int }
type Beverage =
| Tea
| Coffee of Coffee
member x.GetName() =
match FSharpValue.GetUnionFields(x, x.GetType()) with
| (case, _) -> case.Name
当 union case 很简单时,GetName()
可能会带来相同的结果ToString()
:
> let tea = Tea
val tea : Beverage = Tea
> tea.GetName()
val it : string = "Tea"
> tea.ToString()
val it : string = "Tea"
但是,如果 union case 更高级,就会有所不同:。
> let coffee = Coffee ({ Country = "Kenya"; Intensity = 42 })
val coffee : Beverage = Coffee {Country = "Kenya"; Intensity = 42;}
> coffee.GetName()
val it : string = "Coffee"
> coffee.ToString()
val it : string = "Coffee {Country = "Kenya"; Intensity = 42;}"
于 2017-09-05T15:49:15.987 回答
1
此答案为最佳答案提供了附加信息和解决方案。
我刚才有一个案例,上面的答案不起作用。问题是值在接口后面,然后我有时会得到案例名称(咖啡或茶),但主要是类型名称(饮料)。我不明白为什么。我在.NET 5.0 上。
我将功能更改为此,然后它在我的接口 DU 上按预期工作,总是给我案例名称。
open FSharp.Reflection
let GetUnionCaseName (x: obj) =
match FSharpValue.GetUnionFields(x, x.GetType()) with
| case, _ -> case.Name
我知道这与此处的其他答案相似,但这不是成员函数,因此我想应该在任何 DU 上工作,无论是否在接口后面。我还没有测试过在非 DU 类型上使用会发生什么。
type IMessage = interface end
type Beverage = Coffee | Tea
type Car =
| Tesla of model:string
| Ford
interface IMessage
type MySingleCase = MySingleCase of string
type SingleCase2 = SingleCase2 of string interface IMessage
let m1: Beverage = Coffee
let m2: IMessage = (Tesla "Model 3") :> IMessage
let m3 = MySingleCase "x"
let m4 = SingleCase2 "x" :> IMessage
printfn "%s" (GetUnionCaseName m1) // Coffee
printfn "%s" (GetUnionCaseName m2) // Tesla
printfn "%s" (GetUnionCaseName m3) // MySingleCase
printfn "%s" (GetUnionCaseName m4) // SingleCase2
于 2021-01-29T20:12:04.807 回答