F# interactive is a powerful development tool as it allows to run either WinForm or Wpf window and invoke arbitrary code in there.
This gives a way for a 'try-before-you code' approach.
Very often I wish to 'break the boundaries' explicitly and
Is there a workaround to achieve this?
FSI doesn't provide any particular support for this, but you can use Reflection to do the things you want.
open System.Reflection
let field = typeof<MyType>.GetField("fieldName", BindingFlags.NonPublic ||| BindingFlags.Instance)
field.SetValue(myInstance, newVal)
You can go further and define methods or operators to make this even easier. For instance you can set up F#'s dynamic assignment operator to assign to private fields:
let (?<-) o s v =
let field = (o.GetType()).GetField(s, BindingFlags.NonPublic ||| BindingFlags.Instance)
field.SetValue(o,v)
myInstance?fieldName <- newVal (* Note: no quotes around fieldName here *)
Here's some crude code to resolve public or private fields, properties, or methods. Note that there are plenty of ways in which this will fail (in particular, trying to use it on overloaded methods will not work).
open System
open System.Reflection
open Microsoft.FSharp.Reflection
type DynamicHelper =
static member MkMethod<'t,'u> (mi:MethodInfo) o : 't -> 'u=
let typ = typeof<'t>
fun t ->
let args =
if (typ = typeof<unit>) then [||]
else
if not (FSharpType.IsTuple typ) then [| box t |]
else
FSharpValue.GetTupleFields t
mi.Invoke(o, args) :?> 'u
let (?) (o:'a) s : 'b =
let ty = o.GetType()
let field = ty.GetField(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic)
if field <> null then field.GetValue(o) :?> 'b
else
let prop = ty.GetProperty(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic)
if prop <> null then prop.GetValue(o, null) :?> 'b
else
let meth = ty.GetMethod(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic)
let d,r = FSharpType.GetFunctionElements(typeof<'b>)
typeof<DynamicHelper>.GetMethod("MkMethod").MakeGenericMethod([|d;r|]).Invoke(null, [| box meth; box o |]) :?> 'b
With this you can dynamically invoke methods and properties as such:
let (t:System.Type) = "test"?GetType()?BaseType
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With