F # operator "?"

Я только что прочитал информацию о этой странице, а в то время как новый? оператор упоминается, это совершенно неясно, каково было бы его использование.
Может ли кто-нибудь, пожалуйста, дать краткое объяснение, опубликовать код, который был бы отключен от того, как этот оператор будет использоваться и, возможно, упомянуть прецедент?
Изменить: это действительно неудобно, я заметил, что? оператор больше не упоминается в примечаниях к выпуску Don. Любая идея о том, почему?

Ответы

Ответ 1

В этой выпуске F # есть два новых специальных оператора (?) и (? <-). Они не определены, но они доступны для перегрузки, поэтому вы можете сами определить их. Специальный бит заключается в том, как они обрабатывают свой второй операнд: они требуют, чтобы он был допустимым идентификатором F #, но передал его функции, реализующей оператор в виде строки. Другими словами:

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 и т.д.

Ответ 2

Звучит как "?" оператор относится к динамическому языку Runtime (DLR). То есть вы используете его, когда хотите привязываться к члену объекта (метод, свойство) во время выполнения, а не во время компиляции.

Это смешно, потому что я надеялся, что так будет работать динамический вызов членов на С#. Увы, С# предоставляет эту функциональность с помощью псевдо-типа ( "динамический" IIRC). На мой взгляд, это делает код несколько менее понятным (потому что вам нужно отследить объявление переменной, чтобы узнать, связан ли вызов с ранней привязкой или поздней привязкой).

Я не знаю точного синтаксиса, но если бы я должен был догадаться, он либо заменяет, либо увеличивает ".". (точка). Как в:

let x = foo?Bar()

или возможно:

let x = foo.?Bar()

Ответ 3

Существует модуль FSharp.Interop.Dynamic, на nuget, который реализует динамический оператор, используя dlr.

let ex1 = ExpandoObject() in
ex1?Test<-"Hi";
ex1?Test |> should equal "Hi";

Это открытый исходный код, лицензия Apache, вы можете посмотреть реализацию и включить unit test примеры случаев.