Поиск…
Надежное отражение с использованием кодов F #
Отражение полезно, но хрупко. Учти это:
let mi = typeof<System.String>.GetMethod "StartsWith"
Проблемы с таким кодом:
- Код не работает, потому что существует несколько перегрузок
String.StartsWith
- Даже если бы не было никаких перегрузок прямо сейчас, то более поздние версии библиотеки могут добавить перегрузку, приводящую к сбою во время выполнения
- Инструменты рефакторинга, такие как
Rename methods
разбиты с отражением.
Это означает, что мы получаем сбои во время выполнения для того, что известно время компиляции. Это кажется субоптимальным.
Используя цитаты F#
, можно избежать всех вышеперечисленных проблем. Определим некоторые вспомогательные функции:
open FSharp.Quotations
open System.Reflection
let getConstructorInfo (e : Expr<'T>) : ConstructorInfo =
match e with
| Patterns.NewObject (ci, _) -> ci
| _ -> failwithf "Expression has the wrong shape, expected NewObject (_, _) instead got: %A" e
let getMethodInfo (e : Expr<'T>) : MethodInfo =
match e with
| Patterns.Call (_, mi, _) -> mi
| _ -> failwithf "Expression has the wrong shape, expected Call (_, _, _) instead got: %A" e
Мы используем следующие функции:
printfn "%A" <| getMethodInfo <@ "".StartsWith "" @>
printfn "%A" <| getMethodInfo <@ List.singleton 1 @>
printfn "%A" <| getConstructorInfo <@ System.String [||] @>
Это печатает:
Boolean StartsWith(System.String)
Void .ctor(Char[])
Microsoft.FSharp.Collections.FSharpList`1[System.Int32] Singleton[Int32](Int32)
<@ ... @>
означает, что вместо выполнения выражения внутри F#
генерируется дерево выражений, представляющее выражение. <@ "".StartsWith "" @>
генерирует дерево выражений, которое выглядит так: Call (Some (Value ("")), StartsWith, [Value ("")])
. Это дерево выражений соответствует getMethodInfo
и возвращает правильную информацию о методе.
Это устраняет все перечисленные выше проблемы.
Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow