Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Casting issues with dynamic object #17

Open
Freymaurer opened this issue May 2, 2022 · 1 comment
Open

Casting issues with dynamic object #17

Freymaurer opened this issue May 2, 2022 · 1 comment

Comments

@Freymaurer
Copy link
Member

So this is more or less a collection of things i found missing and i am not sure if these are even possible/how to implement them.

  1. Downcasting dynamic objects. Found this issue, when i played around with the DynamicObj.ofJson function i added. It will return a DynamicObj which cannot be downcaster to any type inheriten DynamicObj. The workaround is to use CopyDynamicPropertiesTo on the inerhiting type.
type Logger() =
    inherit DynamicObj()

let logger = Logger()
logger.SetValue ("key", "value")

let dynObj : DynamicObj = DynamicObj()
dynObj.SetValue ("key", "value")

// upcast
let d2 = logger :> DynamicObj // upcast works without issue
d2.TryGetValue "key" // Some "value"

// downcast
dynObj :?> Logger 
// Error: System.InvalidCastException: Unable to cast object of type 'DynamicObj.DynamicObj' to type 'Logger'.

//workaround
dynObj.CopyDynamicPropertiesTo logger 
  1. Cast DynamicObj to (anonymous) record type. This could be especially nice for the TryGetTypedValue member.
type MyRecordType = {|
    key: string
|}

let dynObj : DynamicObj = DynamicObj()
dynObj.SetValue ("key", "value")

dynObj :?> MyRecordType
// Type constraint mismatch. The type 'MyRecordType'  is not compatible with type 'DynamicObj
@Freymaurer
Copy link
Member Author

Soo just made up this poc example, the following could be used in the style of DynamicObj.TryGetTypedValue.

#r "nuget: DynamicObj, 1.0.1"

open DynamicObj

type MyType = {
    Key: string
    Port: int
}

open FSharp.Reflection

type Logger() =
    inherit DynamicObj()

    member inline this.getAsRecordType<'a>() =
        let t = typeof<'a>
        match FSharpType.IsRecord(t) with
        | true -> 
            let fieldValues = 
                FSharpType.GetRecordFields(t) 
                |> Array.map (fun x -> 
                    let vo = this.TryGetValue x.Name
                    if vo.IsNone then failwithf "Field %A does not exist." x.Name else vo.Value
                )
            FSharpValue.MakeRecord(t, fieldValues) :?> 'a
        | false ->
            failwithf "%A is not a record type." t.FullName

let dynObj = Logger()
dynObj.SetValue("Key", "Test Value")
dynObj.SetValue("Port", 8080)

let res = dynObj.getAsRecordType<MyType>()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant