【问题标题】:Downcast using type object in F#在 F# 中使用类型对象向下转换
【发布时间】:2014-08-25 12:35:23
【问题描述】:
let o1 = box SomeType()
let t = typeof<SomeType>

是否可以使用存储在其他对象 (o1) 中的类型信息来向下转换(到 SomeType)一个装箱对象 (o1)?

最终目标是对函数进行一种动态调用。 我在地图中存储带有签名 FSharpFunc 的函数:

// Lack of Covariance/Contravariance force me to define it as obj:
let functions = Map<string,obj>

let invoke f (pre : 'Pre when 'Pre : comparison) (post : 'Post when 'Post : comparison) =
    (unbox<FSharpFunc<'Pre,'Post>> f).Invoke(pre)

每当我在 pre 和 post 中传递正确的类型对象时,此动态调用都会起作用。

知道问题来了。我在表单的映射中也有调用的参数:

let data = Map<string,obj>
let conf = Map<string, Type>

其中 conf 存储数据中每个可能的字符串键的类型。

因此,给定一个功能键和适当的配置,我可以从数据中检索参数以提供功能。但是为了使这些工作,我应该能够使用 conf Types 向下转换数据值。

我怀疑这是不可能的,我知道我正在绕过静态类型安全(我同意)。在这种情况下,任何解决方法或替代方法?

【问题讨论】:

  • 我认为使用反射调用Invoke 函数是最简单的。那么你甚至不需要投射。
  • 是的,这可能是最好的选择。我只是尽可能地坚持静态类型,希望性能更好。

标签: f#


【解决方案1】:

我不确定我是否理解您在此处的目的,因此这不是对您问题的具体回答,而是一些可能对您有所帮助的建议。

一般来说,听起来您想要某种存在类型。听起来像

  • 你有各种类型的数据和

  • 您对该数据进行了操作,并且

  • 您想对数据动态调用这些操作。

为了安全地进行此类操作,您应该将数据(或理想情况下的数据类型)和操作封装在一起,而不是单独封装。当您知道数据的类型和可能对数据进行的操作时,将它们包装在一起,以便程序的其他部分不能只获取数据并尝试对数据执行不安全的任意操作。 (为了使这种封装通用且安全,允许对静态未知类型的数据进行类型安全操作,您需要类似first-class modules。)

作为另一个建议,您可能更愿意装箱和拆箱,而不是装箱整个函数 功能的领域和范围。考虑以下wrapunwrap 函数:

let wrap (a2b: 'a -> 'b) : obj -> obj =
  unbox<'a> >> a2b >> box<'b>

let unwrap (o2o: obj -> obj) : 'a -> 'b =
  box<'a> >> o2o >> unbox<'b>

function 地图会有签名

val functions: Map<string, obj -> obj>

并且会存储包装的函数。要从映射中调用函数,您需要使用所需类型解开先前包装的 o2o 函数:

(unwrap o2o : 'a when 'a: comparison -> 'b when 'b: comparison)

不是类型安全的,但允许灵活的调用。

【讨论】:

  • 感谢您的包装/解包建议。
  • 和你解释的差不多。我有一个由字符串键索引的动态构建的无向操作图,还有一个数据字典(每次执行都不同)。但是数据类型可以在不同的操作中重复使用和组合。我在启动时使用反射(参数的类型和名称)获得函数签名,这将允许我确保编译器的类型正确性。 F# 中的一流模块?
  • 请注意,存在类型可以通过“双重否定”技巧在 F# 中忠实地表示(尽管它很笨重)。见stackoverflow.com/questions/16284680/…
  • @Vesa.A.J.K 另外,如果不需要返回的 'b 类型,我可以避免泛型参数,并让编译器通过以下方式实现调用来推断类型(完成解决方案):让调用( boxed : obj) ( f : obj -> obj) = unwrap f boxed |> box
  • @kvb 我正在努力将存在类型应用于这个特定问题。如果我理解正确,我可以通过使用存在类型签名来避免使用 (obj, obj->obj) 吗?为了深入研究这种方法,我应该打开一个新问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-15
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多