В этом выпуске F # есть два новых «специальных» оператора, (?) И (? <-). Они не определены, но доступны для перегрузки, поэтому вы можете определить их самостоятельно. Специальный бит - это то, как они обрабатывают свой второй операнд: они требуют, чтобы он был действительным идентификатором F #, но передают его функции, реализующей оператор, в виде строки. Другими словами: </p>
a?b
соответствует:
(?) a "b"
и
a?b <- c
соответствует:
(?<-) a "b" c
Очень простое определение этих операторов может быть:
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)
Обратите внимание, что поскольку тип возвращаемого значения для gettor является универсальным, в большинстве случаев вам придется указывать его на сайте использования, т. Е .:
let name = foo?Name : string
хотя вы все еще можете использовать цепочечный вызов (?) (Поскольку первый аргумент (?) Также является общим):
let len = foo?Name?Length : int
Другая, более интересная реализация - это повторное использование метода CallByName, предоставляемого 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
Преимущество заключается в том, что он будет правильно обрабатывать как свойства, так и поля, работать с COM-объектами IDispatch и т. Д.