这是对此的后续上一个问题 https://stackoverflow.com/questions/55877793/f-pattern-matching-on-a-generic-type-map/55878543#55878543,但有不同的转折。
我想编写一个函数,给定一个对象 oMap,如果 oMap 恰好是类型,则返回其计数Map<'k,'v>
,否则为 -1。我的约束:oMap 类型只能在运行时“发现”。
显然“没有内置的方法可以在通用地图上进行模式匹配”。 (请参阅上一个问题的链接),我为此使用反射。
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>
, e.g. :
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
==编辑==
感谢阿斯蒂的建议,这就是对我有用的解决方案:
let gencount (oMap : obj) : int =
let otype = oMap.GetType()
let propt = otype.GetProperty("Count")
try
propt.GetValue(oMap) :?> int
with
| _ -> -1