我需要编写一个函数,该函数带有一个对象(obj
类型和一个键(也是obj
类型),如果对象碰巧是Map,则可以是任何{{ 1}}然后提取其键和值。
困难在于我无法使用泛型类型对函数进行参数化,也无法对泛型类型上的对象进行模式匹配。
我对F#Reflection不熟悉,但是一旦知道Map的键,我就找到了一种获取Map值的方法。使用此示例代码:
Map<'k,'v>
运行上面的代码会将以下内容输出到控制台:
module TestItem =
open System
open Microsoft.FSharp.Reflection
// some uninteresting types for this example, could be anything arbitrary
type Foo = {argF1 : string; argF2 : double; argF3 : bool[]}
type Bar = {argB1 : string; argB2 : double; argB3 : Foo[]}
// and their instances
let foo1 = {argF1 = "foo1"; argF2 = 1.0; argF3 = [| true |]}
let foo2 = {argF1 = "foo2"; argF2 = 2.0; argF3 = [| false |]}
let bar1 = {argB1 = "bar1"; argB2 = 10.0; argB3 = [| foo1 |]}
let bar2 = {argB1 = "bar2"; argB2 = 20.0; argB3 = [| foo2 |]}
// a Map type
type Baz = Map<String,Bar>
let baz : Baz = [| ("bar1", bar1); ("bar2", bar2) |] |> Map.ofArray
let item (oMap : obj) (key : obj) : unit =
let otype = oMap.GetType()
match otype.Name with
| "FSharpMap`2" ->
printfn " -Map object identified"
let prop = otype.GetProperty("Item")
try
let value = prop.GetValue(oMap, [| key |])
printfn " -Value associated to key:\n %s" (value.ToString())
with
| _ ->
printfn " -Key missing from oMap"
| _ ->
printfn " -Not a Map object"
[<EntryPoint>]
let main argv =
printfn "#test with correct key"
let test = item baz "bar1"
printfn "\n#test with incorrect key"
let test = item baz "bar1X"
Console.ReadKey() |> ignore
0 // return exit code 0
现在,要解决我的问题,我只需要找到一种从oMap对象中提取键的方法。
我的问题:如果oMap确实是盒装Map对象,如何完成下面的代码以返回obj []类型的oMap键?
#test with correct key
-Map object identified
-Value associated to key:
{argB1 = "bar1";
argB2 = 10.0;
argB3 = [|{argF1 = "foo1";
argF2 = 1.0;
argF3 = [|true|];}|];}
#test with incorrect key
-Map object identified
-Key missing from oMap
答案 0 :(得分:6)
如果您有一个类型化的映射map
,执行此操作的一种方法是使用序列表达式遍历该映射并使用Key
的{{1}}属性获取键您得到:
KeyValuePair
使用反射(在另一个示例中调用[| for kvp in map -> box kvp.Key |]
的方式)来重构代码以实现此目的将是一场噩梦。您可以做的一个不错的技巧是将其放入通用方法中:
Item
现在,您可以通过反射访问type KeyGetter =
static member GetKeys<'K, 'V when 'K : comparison>(map:Map<'K, 'V>) =
[| for kvp in map -> box kvp.Key |]
方法,获取GetKeys
的类型参数并将其用作方法的Map
和'K
,然后调用以您的'V
作为参数的方法:
oMap
这有效。但是,我还要补充一句,实际上您实际上需要执行此操作,这表明您的系统很可能不是完全正确设计的,因此,我将考虑更改应用程序的设计,从而使您无需执行此类操作的东西。当然,这样做有一些很好的理由,但这应该不太常见。
答案 1 :(得分:2)
这会将键作为字符串数组返回。
let keys (oMap : obj) =
let otype = oMap.GetType()
match otype.Name with
| "FSharpMap`2" ->
printfn " -Map object identified"
(* COMPLETE HERE *)
let map = oMap :?> Map<string, Bar>
let keys = map |> Map.toArray |> Array.map fst
keys
| _ ->
printfn " -Not a Map object"
Array.empty // return empty array
[<EntryPoint>]
let main argv =
printfn "#test with correct key"
let test = item baz "bar1"
printfn "\n#test with incorrect key"
let test = item baz "bar1X"
let keys = keys baz
Console.ReadKey() |> ignore
0 // return exit code 0