gpt4 book ai didi

reflection - 使用反射的 F# 通用 Map.count

转载 作者:行者123 更新时间:2023-12-04 10:55:14 25 4
gpt4 key购买 nike

这是此 previous question 的后续,但有不同的转折。

我想写一个函数,给定一个对象 oMap,如果 oMap 恰好是 Map<'k,'v> 类型,则返回它的计数。 , 否则为 -1。我的约束:oMap 类型只能在运行时“发现”。

显然“没有内置的方法可以在通用 Map 上进行模式匹配。” (请参阅上一个问题的链接),我为此使用了反射。

namespace genericDco

module Test1 =
let gencount (oMap : obj) : int =
let otype = oMap.GetType()
let otypenm = otype.Name

if otypenm = "FSharpMap`2" then
// should work, as oMap of type Map<'a,'b>, but does not. *How to fix this?*
Map.count (unbox<Map<_,_>> oMap)
else
// fails, as oMap is not of any type Map<'a,'b>.
-1

let testfailObj : int = gencount ("foo")

// FAILS
let testsuccessObj : int =
let oMap = [| ("k1", "v1"); ("k1", "v1") |] |> Map.ofArray
gencount (box oMap)

错误是:
System.InvalidCastException: Unable to cast object of type 'Microsoft.FSharp.Collections.FSharpMap`2[System.String,System.String]' to type 'Microsoft.FSharp.Collections.FSharpMap`2[System.IComparable,System.Object]'. at Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions.UnboxGeneric[T](Object source)

我的问题:我应该如何重写上述内容以使其正常工作?

PS:我不是在寻找我们在编译时知道 oMap 类型为 Map<'k,'v> 的解决方案,例如:
module Test2 =
let gencount2<'k,'v when 'k : comparison> (gMap : Map<'k,'v>) : int =
Map.count gMap

let testsuccessStr : int =
let gMap = [| ("k1", "v1"); ("k2", "v2") |] |> Map.ofArray
gencount2<string,string> gMap

let testsuccessDbl : int =
let gMap = [| ("k1", 1.0); ("k2", 2.0); ("k3", 3.0) |] |> Map.ofArray
gencount2<string,double> gMap

== 编辑 ==

感谢 Asti 的建议,这是对我有用的解决方案:
let gencount (oMap : obj) : int =
let otype = oMap.GetType()
let propt = otype.GetProperty("Count")

try
propt.GetValue(oMap) :?> int
with
| _ -> -1

最佳答案

Map.countjust defined as let count m = m.Count ,我们可以直接找 Count属性(property)。

let gencount<'k,'v when 'k : comparison> map =       
let mtype = typeof<Map<'k, 'v>>
let propt = mtype.GetProperty("Count")

if map.GetType() = mtype then
propt.GetValue(map) :?> int
else
-1

测试:
[<EntryPoint>]
let main argv =
let m = Map.ofSeq [ ("a", 1); ("b", 2)]
printfn "%d" (gencount<string, int> m)
printfn "%d" (gencount<string, string> m)
Console.ReadKey() |> ignore
0 // return exit code 0

使用 _如果没有额外的约束信息可用,代替类型将简单地作为对象结束。您使用 unbox当您非常清楚您的值是什么类型时,除了该值是装箱的。

关于reflection - 使用反射的 F# 通用 Map.count,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59242217/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com