Оператор F #?

Я только что прочитал информацию о эта страница, а новая? упоминается оператор, мне совершенно непонятно, как он будет использоваться.
Может ли кто-нибудь дать быстрое объяснение, опубликовать фрагмент кода о том, как будет использоваться этот оператор, и, возможно, упомянуть вариант использования?
< strong> Edit: это действительно неудобно, я заметил, что? Оператор больше не упоминается в примечаниях к выпуску Дона. Есть идеи, почему это так?


person em70    schedule 20.05.2009    source источник


Ответы (3)


В этом выпуске 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)

Обратите внимание, что, поскольку тип возвращаемого значения для получателя является общим, в большинстве случаев вам придется указывать его на сайте использования, то есть:

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

person Pavel Minaev    schedule 22.05.2009
comment
В качестве побочного примечания, очевидно, F # PowerPack включает разумную реализацию по умолчанию. - person Pavel Minaev; 26.11.2009

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

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

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

let x = foo?Bar()

или, может быть:

let x = foo.?Bar()
person Daniel Pratt    schedule 21.05.2009
comment
потому что вам нужно отслеживать объявление переменной, чтобы знать, является ли вызов ранним или поздним ... Вам не нужно отслеживать очень далеко. dynamic должен быть локальной переменной и не может быть членом типа; если вам нужно очень далеко пролистать, чтобы узнать, является ли переменная динамической, скорее всего, вам нужно провести рефакторинг. Кроме того, IDE с радостью сообщит вам тип, если вы наведете курсор на имя переменной ... - person Randolpho; 21.05.2009
comment
Хорошие моменты. Как бы то ни было, есть еще одна причина, по которой я бы предпочел оператор вызова с поздним связыванием, а не реализацию динамического типа: учитывая, что можно подключиться к DLR путем реализации интерфейса, я могу представить сценарий, в котором вы хотели бы выполнять вызовы с ранней привязкой и вызовы с поздней привязкой к одной и той же ссылке. - person Daniel Pratt; 21.05.2009
comment
Из любопытства, каким должен быть тип foo и почему я должен делать это вместо foo.Bar ()? Кроме того, разве я уже не могу достичь того же результата с помощью отражения? - person em70; 21.05.2009
comment
@ emaster70 Сомневаюсь в типе справочника. И да, в большинстве случаев вы можете добиться того же с помощью отражения, однако такой код сложно написать и еще сложнее прочитать. Кроме того, я думаю, что DLR будет поддерживать сценарии, которых нет в отражении. Например, мне кажется, что я припоминаю демонстрацию DLR взаимодействия C # с объектом, определенным в JavaScript. - person Daniel Pratt; 21.05.2009

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

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

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

person jbtule    schedule 29.07.2011