F# - 重载功能

时间:2011-04-21 14:03:11

标签: f#

有没有办法以某种方式重载函数?

让我们来看看这3个功能:

// Returns StringPropertyInfo
let stringProperty (expr:Expr<'a -> string>) (cfg:EntityInfo<'a>) = 
    cfg.Property expr

// Returns DatePropertyInfo
let dateProperty (expr:Expr<'a -> System.DateTime>) (cfg:EntityInfo<'a>) = 
    cfg.Property expr

// Returns BytePropertyInfo
let byteProperty (expr:Expr<'a -> System.Byte>) (cfg:EntityInfo<'a>) =
     cfg.Property expr

有没有办法将它们全部合并到:

let property expr cfg = ....

如果没有,最简单的方法是什么?

4 个答案:

答案 0 :(得分:13)

如果你想使用基于歧视联盟的方法,那么我认为声明更合适(因为你不需要用引号来操纵)。 Alex建议的类型的轻微修改是:

type PropertyInfo<'a> =
  | String of Expr<'a -> string>
  | Date of Expr<'a -> System.DateTime>
  | ...

然后你会写一些类似的东西:

let property (pi:PropertyInfo<'a>) (cfg:EntityInfo<'a>) =
  match pi with
  | String e -> cfg.Property e
  | ...

cfg |> property (String <@ fun e -> e.Foo @>)

另一种选择是将property实现为类型的静态成员,在这种情况下,您可以使用通常的重载(类似于C#)。类似的东西:

type EF = 
  static member property (expr:Expr<'a -> string>) (cfg:EntityInfo<'a>) = 
    cfg.Property expr
  static member property (expr:Expr<'a -> System.DateTime>) (cfg:EntityInfo<'a>) = 
    cfg.Property expr
  static member property (expr:Expr<'a -> System.Byte>) (cfg:EntityInfo<'a>) =
     cfg.Property expr

然后你会写:

cfg |> EF.property <@ e -> e.Foo @>

最后,通过使函数完全通用并进行动态类型测试(以确定使用的返回类型),您还可以使它更简单(但不那么安全)。类似的东西:

let property<'a, 'r> (e:Expr<'a -> 'r>) (cfg:EntityInfo<'a>) =
  if typeof<'r> = typeof<string> then
    // ...

答案 1 :(得分:7)

简短的回答,没有。还有另一个问题涉及这个here

但是,您可以在类等中重载方法,否则.NET集成将无法正常工作。这是一种可能的解决方案,尽管不是我的眼睛,一个漂亮的解决方案。

您可以将它们放在不同的子模块中。

也许你可以创建一个泛型函数并通过其中一个参数决定返回类型。对于某种类型的推断而言,我太过新手了。但是,我肯定会说。

答案 2 :(得分:6)

我认为在这种情况下,受歧视的工会是你的朋友,你会有像

这样的东西
type PropertyInfo = 
| StringPropertyInfo of string
| DatePropertyInfo of System.DateTime
| BytePropertyInfo of byte

然后匹配并执行适当的操作,在一个函数中返回union ...

答案 3 :(得分:2)

获得你正在寻找的东西的一个半丑陋的方法是将其概括一点并使用:

let inline property expr cfg =
    (^t : (member Property : Expr<'a -> 'b> -> 'c)(cfg, expr))

但是,这可以应用于EntityInfo<'a>以外的类型的值,只要它们具有带有正确签名的Property成员。