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

2023-12-29

这是对此的后续上一个问题 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

Since Map.count is 刚刚定义为 https://github.com/fsharp/fsharp/blob/24c798bfcee5d6f91ae2c19888baeb9946744c3a/src/fsharp/FSharp.Core/map.fs#L747 let count m = m.Count,我们可以直接去Count财产。

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 

Test:

[<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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用反射的 F# 通用 Map.count 的相关文章

  • 如何有效地测试action是否用属性(AuthorizeAttribute)修饰?

    我正在使用 MVC 并且有一种情况OnActionExecuting 我需要确定即将执行的Action方法是否用属性修饰 AuthorizeAttribute尤其 我不是问授权是否成功 失败 而是问该方法是否需要授权 对于非 MVC 人员
  • 改进绩效反思 - 我应该考虑哪些替代方案?

    我需要动态地设置对象上的一堆或属性的值 将其称为传输对象 将在短时间内创建相当数量的此类传输对象并设置其属性 我想避免使用反射 还有其他选择吗 如果是的话 有我可以查看的示例实现吗 Use Delegate CreateDelegate h
  • ICSharpCode.Decompiler + Mono.Cecil -> 如何为单个方法生成代码?

    我可以使用 Mono Cecil 和 ICSharpCode Decompiler 生成类型或程序集的代码 但是 如果我尝试为单个方法生成代码 我将收到错误 对象引用未设置为对象的实例 你们能给我任何关于这个的提示吗 提前感谢您的所有帮助
  • 如何通过反射获取透明代理的属性值?

    我的代码接收透明代理而不是原始实例 虽然这var type obj GetType 产生原始类的类型 下面的代码抛出TargetException 对象与目标类型不匹配 var value property GetValue obj nul
  • 在 config/main.php 中找不到 Yii2 模块(不在 /vendor 文件夹下)类

    我在 api 文件夹下创建了一个模块 它本身与 yii2 高级应用程序中的后端和前端处于同一级别 文件夹结构 api 常见的 控制器 楷模 配置 模块 v1 控制器 楷模 运行 测试 网络 在 api config main php 中 r
  • .Net 中可用的并行技术

    我是 Net 平台的新手 我查了一下 发现 Net中有几种做并行计算的方法 任务并行库中的并行任务 即 Net 3 5 PLINQ Net 4 0 异步编程 Net 2 0 异步主要用于执行 I O 繁重的任务 F 有简洁的语法支持这一点
  • int -> int list 与类型 int -> IEnumerable<'a> 不兼容

    Given open System Linq 这是一个可以接受的表达方式 2 3 4 SelectMany fun n gt 1 n 但这不是 2 3 4 SelectMany fun n gt 1 n 错误消息显示 int gt int
  • 获取类 DisplayName 属性值

    我花了最后一个小时试图获得 a 的价值DisplayName应用于 a 的属性Class 我发现从方法和属性中获取属性值很简单 但我在该类上遇到了困难 有人可以帮我解决这个相对较小的问题吗 示例如下 班上 DisplayName Oppor
  • 如何在 F# 中执行 Seq.takeWhile + 一项

    我想编写一个使用谓词过滤序列的函数 但结果还应该包括谓词返回 false 的第一个项目 如果 F 中有一个break关键字 逻辑将是这样的 let myFilter predicate s seq for item in s do yiel
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • Visual Studio 2019 F# NU1101 无法找到包 FSharp.core

    我刚刚开始使用 Microsoft Visual Studio 和 F 我已尽可能地遵循他们的教程 但是当我尝试运行代码时 他们告诉我收到错误 NU1101 Unable to find package FSharp Core No pac
  • 对具有循环引用设计的不可变类的批评以及更好的选择

    我有一个工厂类 它创建带有循环引用的对象 我也希望它们是不可变的 在某种意义上 所以我使用以下技术 使用某种闭包
  • 属性中的类型约束

    我想用自定义属性编写枚举 例如 public enum SomeEnum long SomeAttribute
  • 在 Silverlight 中使用反射来迭代所有引用程序集中的类型?

    silverlight中有类似的东西吗 var assemblies AppDomain CurrentDomain GetAssemblies http msdn microsoft com en us library system ap
  • 尝试使用连续传递风格来避免极小极大算法的堆栈溢出

    我的目标摘要 弄清楚如何使用连续传递样式来避免在使用我认为无法进行尾递归的算法时出现堆栈溢出 或者 找到一种方法使函数成为尾递归 Details 我是 F 以及一般函数式编程 的新手 我正在尝试通过 alpha beta 剪枝实现极小极大算
  • Groovy:在调用任何方法之前和之后透明地执行代码

    假设我们有一个带有一些方法 静态或非静态 的常规类 我想要做的是在调用此类的每个方法之前和之后执行一些代码 而无需触摸该类 也无需动态操作每个方法内部的代码 我尝试使用 groovy 元类 获取元类的所有方法 然后用包装方法动态替换每个方法
  • 按任何属性对列表进行排序的更好方法

    我的方法接收所有 DataTables 参数 以按单击的列对表进行排序 我从每个页面列表的控制器调用此方法 我正在寻找一种更好的方法来执行此操作 例如适用于所有类型的通用方法 string int decimal double bool n
  • 如何获取调用方法的参数值?

    Question 我正在编写一些需要能够获得的代码values调用该类的方法的参数 我知道如何一直获取 ParameterInfo 数组 但我不知道如何获取值 这可能吗 如果是 我认为这与使用 MethodInfo 对象中的 MethodB
  • 序列化/反序列化和非默认构造函数

    考虑这个类 Persistable public sealed class FileMoveTask TaskBase PersistMember public string SourceFilePath get private set P
  • 结合记忆和尾递归

    是否有可能以某种方式将记忆和尾递归结合起来 我目前正在学习 F 理解这两个概念 但似乎无法将它们结合起来 假设我有以下内容memoize函数 来自现实世界的函数式编程 http www manning com petricek let me

随机推荐