Frage

Ich habe eine Funktion, die verschiedene Typen zurückgeben kann, und ich verwende Diskriminierte Gewerkschaft dafür. Was ich brauche, ist eine Konvertierung von einem Typ in diskriminierter Gewerkschaft in einen anderen Typ. Auch einige der Typen können auf alle anderen Typen konvertiert werden (Saite), aber einige der Typen können nur in String konvertiert werden ((Mycustomtype)

Dazu habe ich die Mitgliedsmethode hinzugefügt Konvertieren zu zum 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())

Ich mag eine solche Konstruktion nicht, denn wenn ich mehr Typen hinzufüge, muss ich viele Änderungen vornehmen: Mytypes, Ergebnistyp und auch an mehreren Stellen in der Konvertieren zu Mitgliedsfunktion.

Kann jemand eine bessere Lösung für die Konvertierung solcher Typen vorschlagen?

Danke im Voraus

War es hilfreich?

Lösung

Mit einem etwas anderen Design ist es möglich, auszunutzen System.Convert.ChangeType und die Tatsache, dass die Konstrukteure diskriminierter Gewerkschaften tatsächlich Funktionen sind:

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

Bearbeiten: Sobald Sie mehr benutzerdefinierte Typen hinzufügen, hilft dies nicht viel.

Vielleicht sollten Sie Ihre benutzerdefinierten Typen implementieren lassen IConvertible. Dann können Sie den Sonderfallcode aus entfernen ConvertTo und verlassen sich völlig auf System.Convert.ChangeType.

Sie müssten immer noch jeden benutzerdefinierten Typ erweitern ToObject Implementierung Wenn Sie einen neuen benutzerdefinierten Typ hinzufügen. Ob das wirklich besser ist als ein Zentral ConvertToFunktion ist fraglich.

Andere Tipps

Warum möchten Sie zunächst mit dem Typ Conversion konvertiert werden? Diskriminierte Gewerkschaften sind ein guter Weg, um Informationen zu verbergen, bis Sie sie benötigen, und die abstrakte Komplexität weg. Im Allgemeinen haben Sie eine Übereinstimmungsanweisung in einer Funktion, die diesen Typ verbraucht, und dann haben Sie nur dann gegossen, wenn Sie müssen.

Wenn Sie versuchen, eine Art von Parser oder Sprachmaschine zu erstellen, haben Sie keine andere Wahl, als alle Besetzungen oder zumindest deren Fehlerzustände zu definieren. Wenn es Ihnen nichts ausmachen würde, herauszufinden, warum / wofür Sie dies verwenden würden, könnte ich vielleicht einen anderen Ansatz vorschlagen.

Abgesehen von: F# und .NET im Allgemeinen unterstützt die Überladung von Rückgabetypen nicht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top