tags:

views:

110

answers:

3

I have an object of type FSharpOption, but I don't know it's depth. It could be any of...

FSharpOption<Int32>
FSharpOption<FSharpOption<Int32>>
FSharpOption<FSharpOption<FSharpOption<Int32>>>
FSharpOption<FSharpOption<FSharpOption<FSharpOption<Int32>>>>
etc.

Edit: Also note that it isn't necessarily an Int32. It could be any underlying type.

How do I get at the underling value using VB or C#?

+2  A: 

I can't help but wonder how you got into this state in the first place.

That said, assuming the static type is 'object', then I guess you'll have to see if its .GetType() is the generic type definition of FSharpOption`1, and use reflection (or 'dynamic') to unwrap one level and try again...

I am unclear how this is an F# question, since you want the answer in C# or VB, and the same question could be asked of any Foo<T> type.

That all said, here's some C# 4.0 code:

    object o = FS.Foo.F(3);
    while (o.GetType().IsGenericType && 
           o.GetType().GetGenericTypeDefinition() == 
              typeof(Microsoft.FSharp.Core.FSharpOption<>))
    {
        dynamic d = o;
        o = d.Value;
    }
    Console.WriteLine(o);

and some F# code:

namespace FS

type Foo() = 
    static member F x =
        match x with
        | 1 -> Some 42 |> box
        | 2 -> Some(Some "forty-two") |> box
        | 3 -> Some(Some(Some 42)) |> box
        | _ -> failwith "no"

EDIT note that I changed it to show the strategy works even if it contains things other than just ints.

Brian
(realization) Hey wow, I used 'dynamic' without even really thinking about it!
Brian
I am working on a generic interop library for C#/VB applciations that need to deal with F# types. This is a bit of an edge case, but so long as F# supports unlimited nesting I need to account for it.
Jonathan Allen
I don't understand what you mean my "F# supports unlimited nesting". You could "have the same problem" with System.Collections.Generic.List<T>. "I have an object that's int, or List<int>, or List<List<int>>, or ..." Nothing F# here.
Brian
That is exactly what I mean by unlimited nesting. As a contrast, Nullable<T> cannot be nested.
Jonathan Allen
+1  A: 

Ok, so this is what I have so far. Any suggestions on improving it?

Option Strict Off
Imports Microsoft.FSharp.Core

Public Module FSharpInterop
    Public Function OptionGetUnderlyingValue(ByVal value As Object) As Object
        If value Is Nothing Then Return Nothing
        Dim temp = value
        Do While temp.GetType.Name = "FSharpOption`1"
            temp = OptionModule.GetValue(temp)
            If temp Is Nothing Then Return Nothing
        Loop
        Return temp
    End Function
End Module
Jonathan Allen
+1  A: 

That may not be version independent... how about this minor variation with no dependency on FSharp.Core?

static object OptionGetUnderlyingValue(object obj)
{
    while (obj != null && obj.GetType().Name == "FSharpOption`1")
    {
        PropertyInfo pi = obj.GetType().GetProperty("Value");
        Contract.Assert(pi != null);
        obj = pi.GetValue(obj, null);
    }

    return obj;
}
Nathan Howell
Nice touch. It might be a little slower, but then again it might not be.
Jonathan Allen