Get default member value of a type with reflection

Viewed 26

I have multiple types with a member of memberName

type User = {
    user_id: int
    username: string
    email: string
} with member this.memberName = "woo"

Then I want to have a function that can take a type argument of any type with that member and return the value of it.

My logic to this was to create a default instance of that type and check that way, but is returning a NullReferenceException

let inline GetMemberName< 'x when  'x: (member memberName: string)> () =
        let defaultType = Unchecked.defaultof<'x>
        ((^x) : (member memberName: string) defaultType)

GetMemberName<User> ()

Thanks

1 Answers

You are getting NullReferenceException because you are accessing an instance member, but you are creating the instance using Unchecked.defaultof which returns null. This function is really an unsafe hack for interoperating with .NET, where any (non-value) type can have null - but this is not something you typically want in F#.

As far as I can see, you could turn this into a static member, which does not need an instance:

type User = 
  { user_id: int
    username: string
    email: string } 
  static member memberName = "woo"


let inline GetMemberName< 'x when  'x: (static member memberName: string)> () =
        ((^x) : (static member memberName: string) ())

GetMemberName<User> ()

If you actually wanted to initialize an F# type to a sensible default value, you could come up with a mechanism to do this using Reflection, but it would be hard and (in general) impossible as not all types have a reasonable default value.

That said, for records with integers and strings, something like this would be a start:

open Microsoft.FSharp.Reflection

let flds = FSharpType.GetRecordFields(typeof<User>)
let vals = 
  [| for fld in flds -> 
        if fld.PropertyType = typeof<int> then box 0
        elif fld.PropertyType = typeof<string> then box ""
        else null |]
let user = FSharpValue.MakeRecord(typeof<User>, vals)
Related