There are two new "special" operators in this F# release, (?) and (?<-). They are not defined, but they are available for overloading, so you can define them yourself. The special bit is how they treat their 2nd operand: they require it to be a valid F# identifier, but pass it to function implementing the operator as a string. In other words:
a?b
is desugared to:
(?) a "b"
and:
a?b <- c
is desugared to:
(?<-) a "b" c
A very simple definition of those operators could be:
let inline (?) (obj: 'a) (propName: string) : 'b =
let propInfo = typeof<'a>.GetProperty(propName)
propInfo.GetValue(obj, null) :?> 'b
let inline (?<-) (obj: 'a) (propName: string) (value: 'b) =
let propInfo = typeof<'a>.GetProperty(propName)
propInfo.SetValue(obj, value, null)
Note that since the return type for the gettor is generic, you'll have to specify it at use site in most cases, i.e.:
let name = foo?Name : string
though you can still chain-call (?) (since first argument of (?) is also generic):
let len = foo?Name?Length : int
Another, more interesting, implementation is to re-use CallByName method provided by VB:
open Microsoft.VisualBasic
let inline (?) (obj: 'a) (propName: string) : 'b =
Interaction.CallByName(obj, propName, CallType.Get, null) :?> 'b //'
let inline (?<-) (obj: 'a) (propName: string) (value: 'b) =
Interaction.CallByName(obj, propName, CallType.Set, [| (value :> obj) |])
|> ignore
The advantage of that is that it will handle both properties and fields correctly, work with IDispatch COM objects, etc.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…