Преобразование между типами в дискриминационных союзах - PullRequest
4 голосов
/ 15 марта 2011

У меня есть функция, которая может возвращать разные типы, и для этого я использую различимое объединение .Что мне нужно, так это преобразовать один тип в различном объединении в другой тип.Также некоторые типы могут быть преобразованы во все другие типы ( String ), но некоторые типы могут быть преобразованы только в String ( MyCustomType )

.Я добавил метод-член ConvertTo к ResultType:

type MyTypes = 
   | Boolean       = 1
   | Integer       = 2
   | Decimal       = 3
   | Double        = 4
   | String        = 5
   | MyCustomType  = 6

type ResultType = 
   | Boolean of bool
   | Integer of int
   | Decimal of decimal
   | Double of double
   | String of string
   | MyCustomType of MyCustomType

   with 
     member this.ConvertTo(newType: MyTypes) = 
       match this with 
       | ResultType.Boolean(value) -> 
           match newType with 
           | MyTypes.Boolean -> 
              this
           | MyTypes.Integer -> 
              ResultType.Integer(if value then 1 else 0)
          ...
       | ResultType.MyCustomType(value) -> 
           match newType with 
           | MyTypes.MyCustomType -> 
              this
           | MyTypes.String -> 
              ResultType.String(value.ToString()) 
           | _ -> 
              failwithf "Conversion from MyCustomType to %s is not supported" (newType.ToString())

Мне не нравится такая конструкция, потому что, если я добавляю больше типов, это требует от меня много изменений: MyTypes , ResultType , а также в нескольких местах в функции-члене ConvertTo .

Может кто-нибудь предложить лучшее решение для таких типовконвертация?

Заранее спасибо

Ответы [ 2 ]

8 голосов
/ 15 марта 2011

С немного другим дизайном можно использовать System.Convert.ChangeType и тот факт, что конструкторы различимых объединений на самом деле являются функциями:

// statically typed wrapper for System.Convert.ChangeType
let conv a : 'T = System.Convert.ChangeType(a, typeof<'T>) :?> 'T

type MyCustomType() = class end

type ResultType = 
  | Boolean of bool
  | Integer of int
  | Decimal of decimal
  | Double of double
  | String of string
  | MyCustomType of MyCustomType
  with
    member this.ConvertTo (newType:'T->ResultType) =
      match this with
      | Boolean b -> newType( conv b )
      | Integer i -> newType( conv i )
      | Decimal d -> newType( conv d )
      | Double d -> newType( conv d )
      | String s -> newType( conv s )
      | MyCustomType m ->
         if typeof<'T> <> typeof<string> then
            raise (new System.InvalidCastException("MyCustomType can only be converted to String"))
         else
            String (m.ToString())

let i = Integer 42

let b = i.ConvertTo Boolean
printfn "%A" b

let d = i.ConvertTo Decimal
printfn "%A" d

let d2 = i.ConvertTo Double
printfn "%A" d2

let s = i.ConvertTo String
printfn "%A" s

//let mi = i.ConvertTo MyCustomType  // throws InvalidCastException

let m = MyCustomType (new MyCustomType())
let sm = m.ConvertTo String
printfn "%A" sm

//let im = m.ConvertTo Integer // throws InvalidCastException

РЕДАКТИРОВАТЬ: после добавления дополнительных пользовательских типов, это будетне сильно поможет.

Может быть, вам следует заставить свои пользовательские типы реализовывать IConvertible.Затем вы можете удалить код специального случая из ConvertTo и полностью положиться на System.Convert.ChangeType.

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

2 голосов
/ 15 марта 2011

Почему вы хотите начать преобразование типов?Дискриминационные союзы - это хороший способ скрыть информацию о типах, пока она вам не понадобится, и не отвлекать внимание от сложности.Как правило, у вас есть оператор соответствия в функции, которая использует этот тип, а затем вы приводите только при необходимости.

Если вы пытаетесь создать какой-либо синтаксический анализатор или языковой движок, у вас нет другого выбора, кроме как определить все приведенные типы или, по крайней мере, их состояния ошибок.Если вы не возражаете уточнить, почему / для чего вы будете использовать это, возможно, я мог бы предложить другой подход.

За исключением: F # и .NET в целом не поддерживают перегрузку типов возврата.*

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