F # - Функции перегрузки - PullRequest
       2

F # - Функции перегрузки

11 голосов
/ 21 апреля 2011

Есть ли способ как-то перегрузить функцию?

Давайте возьмем эти 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 ]

13 голосов
/ 21 апреля 2011

Если вы хотите использовать подход, основанный на дискриминационных союзах, то я думаю, что объявление более подходит (так как вам не нужно манипулировать цитатами).Небольшая модификация типа, предложенного Алексом:

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
    // ...
7 голосов
/ 21 апреля 2011

Краткий ответ, нет.Есть еще один вопрос, касающийся этого здесь .

Однако вы можете перегружать методы в классах и т. Д. В противном случае интеграция .NET не будет работать слишком хорошо.Это одно из возможных решений, хотя и не в моих глазах.

Вы можете поместить их в разные подмодули.

Возможно, вы могли бы сделать обобщенную функцию и определить тип возвращаемого значения черезодин из параметров.Я слишком новичок, когда дело доходит до определения типа, чтобы сказать наверняка.

6 голосов
/ 21 апреля 2011

я думаю, что в этом случае ваш друг - дискриминируемый союз, у вас будет что-то вроде

type PropertyInfo = 
| StringPropertyInfo of string
| DatePropertyInfo of System.DateTime
| BytePropertyInfo of byte

, а затем вы найдете его и выполните соответствующее действие, возвращая объединение в одной функции ...

2 голосов
/ 21 апреля 2011

Один полу-уродливый способ получить то, что вы ищете, это немного обобщить и использовать:

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

Однако это может быть применено к значениям типов, отличных от EntityInfo<'a>, если они имеют член Property с правильной подписью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...