in C# WPF we can use nameof as in
public class MyControl : Control
{
private static readonly DependencyProperty _myProperty =
DependencyProperty.Register(nameof(MyProperty), typeof(int), typeof(MyControl));
public int MyProperty
{
get => (int)GetValue(_myProperty);
set => SetValue(_myProperty, value);
}
}
but in F# this doesn't work
type MyControl() as this =
inherit Control()
static let _myProperty =
DependencyProperty.Register(nameof MyProperty, typeof<int>, typeof<MyControl>) //The value or constructor 'Bars' is not defined.
member this.MyProperty
with get() = this.GetValue(_myProperty) :?> int
and set(value: int) = this.SetValue(_myProperty, value)
The easiest way is to use a string "MyProperty" but this has the notorious error prone effect when renaming the property if we forget to change the string.
Is there a way to preserve the nameof safety that C# gives in F#?
A way I found is
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
let getPropertyName (expr: Expr<'T -> 'U>) =
match expr with
| Lambda(_, PropertyGet(_, propInfo, _)) -> propInfo.Name
| _ -> failwith "Invalid expression: Expected a property getter."
type MyControl() as this =
inherit Control()
static let _myProperty =
DependencyProperty.Register(getPropertyName <@ fun (c: MyControl) -> c.MyProperty @>, typeof<int>, typeof<MyControl>)
member this.MyProperty
with get() = this.GetValue(_myProperty) :?> int
and set(value: int) = this.SetValue(_myProperty, value)
but it is clearly cumbersome.
It seems a limit of the nameof feature in F# against C#. Is there a better way?
This is a known limitation when using nameof
on an instance member. The recommended workaround is to use Unchecked.defaultof
:
static let _myProperty =
let name = nameof Unchecked.defaultof<MyControl>.MyProperty
DependencyProperty.Register(name, typeof<int>, typeof<MyControl>)