I have an idea ;)I had some problems in FsCheck with this kind of thing. Turns out that union cases are compiled to a superclass representing the static type of the union, with subclasses for each union case, and so that doing GetType() on a union value confused reflection because the type returned is not recognized as a union type by some reflection methods (only the superclass, or the "static" type, is recognized as such, and GetType on a value of course returns the type of a subclass). I can look up the specifics if you want. I remembered: "beware of using value.GetType to do reflection on union cases" and I see that's what you're doing, so for what it's worth...For a quick check if that is the problem: try gettting the baseclass of the type returned by GetType, see if that works.

By on 4/30/2009 12:16 AM ()

yeah, if you can dig that up, that'd help a ton, thanks. i'll dig at it from my end. the snippet i posted up does seem to work for my scenarios, but it's obviously rather fragile and dependent on the current internal implementation of unions.

By on 4/30/2009 10:16 AM ()

It seems that at one point in FsCheck, to avoid problems, I replaced all calls to function like

1
let unwrap (t:obj)//withlet unwrap<'a>()

Which gets the static type of the thing if you use typeof, instead of the dynamic type if you use GetType. As I explained above, for union cases, there is a difference. I remember making this decision to avoid the kind of problems you mention. As for your second issue, I haven't really looked at the code long enough to really understand it, but did you consider using PreComputeUnionTagReader and friends?

By on 5/1/2009 8:43 AM ()

for the record, here's what i've ended up doing, and it begs another question. given a discriminator instance, how do i get at it's value dynamically? i've come up with a solution, but it's rather gnarly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    /// recursively removes discriminators from the given value, until only the value remains
    let rec unwrap (v: obj) =
        if v = null then v
        else
            let t = v.GetType()
            if not <| FSharpType.IsUnion t then v
            else
                let caseInfo = FSharpType.GetUnionCases(t)
                let field =
                    match 
                        // there doesn't seem to be a clean way to identify which specific 
                        // discriminator we're holding on to. as a result, we have to rumage through
                        // and say that
                        //      if there's one union case and there's one value on it, done
                        //      if there's more than one value on the union case, we have no way of picking. bye.
                        //      if there's more than one union case, we can keep looking until
                        //          we find a single discriminator, with a single value, whose accessor 
                        //          property's name matches a property name that our instance has
                        seq { for case in caseInfo -> case.GetFields() } |>
                        Seq.first (fun (f: PropertyInfo array) -> 
                                    if not (Array.length f = 1) then None 
                                    else
                                        let prop = t.GetProperty(f.[0].Name)
                                        if prop = null then None
                                        else Some prop
                                    ) with
                    | None -> null
                    | Some p -> p

                if field = null then v                        
                else field.GetValue(v, null)
By on 4/29/2009 3:58 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper