kvb (which does not do the same, since it assumes that the type test has completed successfully) can be modified to create a similar pattern:
let (|Value|_|) x value = match box value with | :? 'T as y when x = y -> Some() | _ -> None
However, there is a subtle difference in performance. The original active template is converted to:
public static FSharpOption<T> |Value|_|<a, T>(a value) { object obj = value; if (!LanguagePrimitives.IntrinsicFunctions.TypeTestGeneric<T>(obj)) { return null; } return FSharpOption<T>.Some((T)((object)obj)); }
those. he performs type test and casting. This use ( match x with Value "" -> ... ) means:
FSharpOption<string> fSharpOption = MyModule.|Value|_|<object, string>(obj); if (fSharpOption != null && string.Equals(fSharpOption.Value, "")) { ... }
In particular, the typed value returned from the template is mapped using typical compiler transformations for templates ( string.Equals for strings).
The updated template is converted to:
public static FSharpOption<Unit> |Value|_|<T, a>(T x, a value) { object obj = value; if (LanguagePrimitives.IntrinsicFunctions.TypeTestGeneric<T>(obj)) { T y = (T)((object)obj); T y3 = y; if (LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<T>(x, y3)) { T y2 = (T)((object)obj); return FSharpOption<Unit>.Some(null); } } return null; }
which uses general equality and is less efficient than matching with a literal. Usage is a bit simpler since equality is baked in the template:
FSharpOption<Unit> fSharpOption = MyModule.|Value|_|<string, object>("", obj); if (fSharpOption != null) { ... }
Anyway, it works. But I like the original better.
Daniel
source share