mardi 28 avril 2015

Copying a discriminated union object

I want to make a copy of an object that is of a discriminated union type, with one or two particular fields assigned different values and any other fields copied straight across.

The tricky part is that I'm trying to write a function to do this, that will keep working unchanged even as more cases are added to the union, so I can't use match; instead, I'm looking for a solution that uses reflection to examine the fields of the particular case. Here's what I have so far on the reverse side, extracting values from an object regardless of its exact type:

let case a =
    match FSharpValue.GetUnionFields (a, typeof<Term>) with
    | info, _ ->
        info

let unpack a =
    let fields = List.ofSeq ((case a).GetFields ())
    List.collect
        (fun (field: PropertyInfo) ->
            let t = field.PropertyType
            if t = typeof<Term> then
                [field.GetValue a :?> Term]
            elif t.IsGenericType && t.GenericTypeArguments.[0] = typeof<Term> then
                field.GetValue a :?> Term list
            else
               []
        )
        fields

And I'm trying to write a function that starts off something like:

let pack a xs =
    let fields = List.ofSeq ((case a).GetFields ())
    ...

It occurred to me to try to use MemberwiseClone but that's protected, so can't be used outside subclasses. I'm probably looking for something like 'create a new object of this type, then step through the fields copying across or filling in values as appropriate' though I'm not quite sure what 'this type' would be, since GetType doesn't work on discriminated unions. What's the best way to go about it?





Aucun commentaire:

Enregistrer un commentaire