Frage

Gday Alle,

Ich habe in einigem F # in der letzten Zeit Dilettantismus und ich kam mit den folgenden String-Builder, die ich von einigem C # -Code portierte. Er wandelt ein Objekt in einen String, sofern sie eine Regex in den Attributen definiert gibt. Es ist wahrscheinlich übertrieben für die Aufgabe zur Hand, aber sein zu Lernzwecken.

Derzeit ist das Build Mitglied nutzt einen veränderlichen String-Variable updatedTemplate. Ich habe mein Gehirn wurde Abstich einen Weg dies zu tun arbeiten, ohne veränderbare Objekte ohne Erfolg. Das bringt mich auf meine Frage.

Ist es möglich, die Buildelementfunktion ohne veränderbare Objekte zu implementieren?

Cheers,

Michael

//The Validation Attribute
type public InputRegexAttribute public (format : string) as this =
    inherit Attribute()
    member self.Format with get() = format

//The class definition
type public Foo public (firstName, familyName) as this =
    [<InputRegex("^[a-zA-Z\s]+$")>]
    member self.FirstName with get() = firstName 

    [<InputRegex("^[a-zA-Z\s]+$")>]
    member self.FamilyName with get() = familyName 

module ObjectExtensions =
    type System.Object with
        member this.BuildString template =
            let mutable updatedTemplate : string  = template
            for prop in this.GetType().GetProperties() do
                for attribute in prop.GetCustomAttributes(typeof<InputRegexAttribute>,true).Cast<InputRegexAttribute>() do
                    let regex = new Regex(attribute.Format)
                    let value = prop.GetValue(this, null).ToString()
                    if regex.IsMatch(value) then
                        updatedTemplate <- updatedTemplate.Replace("{" + prop.Name + "}", value)
                    else
                        raise (new Exception "Regex Failed")
            updatedTemplate

open ObjectExtensions
try
    let foo = new Foo("Jane", "Doe")
    let out = foo.BuildInputString("Hello {FirstName} {FamilyName}! How Are you?")
    printf "%s" out
with | e -> printf "%s" e.Message
War es hilfreich?

Lösung

Ich denke, man kann immer „mit nur einem Effekt (mutiert eine lokale Variable) für Schleife über eine Sequenz“ in den Code einer Transformation, die von der wandelbaren entledigt; hier ist ein Beispiel für die allgemeine Transformation:

let inputSeq = [1;2;3]

// original mutable
let mutable x = ""
for n in inputSeq do
    let nStr = n.ToString()
    x <- x + nStr
printfn "result: '%s'" x

// immutable
let result = 
    inputSeq |> Seq.fold (fun x n ->
        // the 'loop' body, which returns
        // a new value rather than updating a mutable
        let nStr = n.ToString()
        x + nStr
    ) ""  // the initial value
printfn "result: '%s'" result

Ihr spezielles Beispiel hat Schleifen verschachtelt, also hier ist ein Beispiel für die gleiche Art von mechanischen zeigen in zwei Schritten umwandeln:

let inputSeq1 = [1;2;3]
let inputSeq2 = ["A";"B"]

let Original() = 
    let mutable x = ""
    for n in inputSeq1 do
        for s in inputSeq2 do
            let nStr = n.ToString()
            x <- x + nStr + s
    printfn "result: '%s'" x

let FirstTransformInnerLoopToFold() = 
    let mutable x = ""
    for n in inputSeq1 do
        x <- inputSeq2 |> Seq.fold (fun x2 s ->
            let nStr = n.ToString()
            x2 + nStr + s
        ) x
    printfn "result: '%s'" x

let NextTransformOuterLoopToFold() = 
    let result = 
        inputSeq1 |> Seq.fold (fun x3 n ->
            inputSeq2 |> Seq.fold (fun x2 s ->
                let nStr = n.ToString()
                x2 + nStr + s
            ) x3
        ) ""
    printfn "result: '%s'" result

(In dem obigen Code, habe ich die ‚x2‘ Namen und ‚x3‘ deutlicher machen Scoping, aber Sie können nur den Namen verwenden ‚x‘ im gesamten Gebäude.)

Es kann sinnvoll sein, um zu versuchen, dieselbe zu tun, auf dem Beispiel-Code umwandeln und Ihre eigene Antwort posten. Dies wird nicht unbedingt den meisten idiomatischen Code ergibt, kann aber für Schleife in einen Seq.fold Anruf bei der Umwandlung eine Übung sein.

(Das heißt, in diesem Beispiel das ganze Ziel ist meist eine akademische Übung -. Der Code mit der wandelbar ist ‚fein‘)

Andere Tipps

Ich habe nicht die Zeit, dies als Code zu schreiben, aber:

  • Schreiben Sie eine Funktion, die innerste Teil darstellt, eine Zeichenfolge (das Ergebnis bisher) und ein Tupel der Immobilie und das Attribut nehmen und die Zeichenfolge nach dem Austausch zurück.
  • Verwenden Sie seq.map_concat gehen aus der Reihe von Eigenschaften von GetProperties() in eine Folge von (Eigenschaft, ein Attribut) Tupel zurückgegeben.
  • Verwenden Sie seq.fold mit den vorherigen zwei Bits, die die gesamte Transformation zu tun, die ursprüngliche Vorlage als Ausgangswert für die Aggregation verwendet wird. Das Gesamtergebnis wird die endgültige Fassung String sein.

Ist das sinnvoll?

Ein rein funktionaler Ansatz:

module ObjectExtensions =
type System.Object with
    member this.BuildString template =
        let properties = Array.to_list (this.GetType().GetProperties())
        let rec updateFromProperties (pps : Reflection.PropertyInfo list) template =
            if pps = List.Empty then
                template
            else 
                let property = List.hd pps
                let attributes = Array.to_list (property.GetCustomAttributes(typeof<InputRegexAttribute>,true))
                let rec updateFromAttributes (ats : obj list) (prop : Reflection.PropertyInfo) (template : string) =
                    if ats = List.Empty then
                        template
                    else
                        let a = (List.hd ats) :?> InputRegexAttribute
                        let regex = new Regex(a.Format)
                        let value = prop.GetValue(this, null).ToString()
                        if regex.IsMatch(value) then
                            template.Replace("{" + prop.Name + "}", value)
                        else
                            raise (new Exception "Regex Failed\n")
                updateFromProperties(List.tl pps) (updateFromAttributes attributes property template)
        updateFromProperties properties template
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top