error caller c# c#-6.0 .net-4.6 callermembername nameof

caller - nameof c#



¿Hay algún beneficio de usar el operador nameof en lugar del atributo CallerMemberNameAttribute para notificar cambios de propiedad en.NET 4.5.3? (2)

Con la llegada de .NET 4.5.3, los desarrolladores de WPF ahora tienen tres (o más) formas de notificar a la Interfaz INotifyPropertyChanged de los cambios de propiedad. Básicamente, mi pregunta es ¿Cuál de los dos métodos introducidos a partir de .NET 4.5 es la forma más eficiente de notificar cambios en las propiedades y si de alguna manera tiene algún beneficio cuando se usa en WPF?

Fondo

Para aquellos que no están tan familiarizados con este tema, aquí están los tres métodos principales. El primero es el método original, más propenso a errores, de simplemente pasar una cadena:

public string TestValue { get { return testValue; } set { testValue = value; NotifyPropertyChanged("TestValue"); } } protected virtual void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } }

El segundo método fue introducido en .NET 4.5; el CallerMemberNameAttribute :

public string TestValue { get { return testValue; } set { testValue = value; NotifyPropertyChanged(); } } protected virtual void NotifyPropertyChanged([CallerMemberName]string propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } }

El tercer y más reciente método fue (o pronto será) introducido en C # 6.0 como parte de .NET 4.5.3; el nameof operador :

public string TestValue { get { return testValue; } set { testValue = value; NotifyPropertyChanged(nameof(TestValue)); } } protected virtual void NotifyPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }

Mi propia suposición sería que el método original, más propenso a errores, de simplemente pasar una cadena sería el más eficiente, ya que solo puedo imaginar que los otros dos métodos usan alguna forma de reflexión. Sin embargo, estoy realmente interesado en descubrir cuál de los otros dos métodos es más eficiente y si realmente habría alguna diferencia entre el uso del atributo CallerMemberNameAttribute y el nameof operador en un contexto WPF.


Acerca de la eficiencia: usando una cadena directamente, CallerMemberNameAttribute , nameof son exactamente iguales ya que el compilador inyecta la cadena en tiempo de compilación. No hay reflexión involucrada.

Podemos ver que utilizando TryRoslyn que produce esto para CallerMemberNameAttribute :

public string TestValue { get { return this.testValue; } set { this.testValue = value; this.NotifyPropertyChanged("TestValue"); } } protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "") { if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } }

Y esto para nameof :

public string TestValue { get { return this.testValue; } set { this.testValue = value; this.NotifyPropertyChanged("TestValue"); } } protected virtual void NotifyPropertyChanged(string propertyName) { if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } }

Como en tiempo de ejecución, todas las opciones son simplemente una string no hay problema con el contexto WPF.

Acerca de la conveniencia: CallerMemberNameAttribute requiere que tengas un parámetro opcional, mientras que nameof no lo hace, pero nameof requiere que especifiques la propiedad, mientras que CallerMemberNameAttribute no.

Predigo que nameof sería tan popular que sería mucho más sencillo usarlo.


El CallerMemberNameAttribute solo se puede usar en la función llamada para obtener el nombre de la función del llamante.

El operador nameof va mucho más allá de eso. Se puede utilizar en cualquier lugar.

Si desea razonar al respecto solo en el ámbito del enlace de datos de WPF, tome este ejemplo:

public string FullName { get { return string.Format( "{0} {1}", this.firstName, this.lastName); } } public string FirstName { get { return this.firstName; } set { if (value != this.firstName) { this.firstName = value; NotifyPropertyChanged(nameof(FirstName)); NotifyPropertyChanged(nameof(FullName)); } } } public string LasttName { get { return this.lastName; } set { if (value != this.lastName) { this.lastName = value; NotifyPropertyChanged(nameof(LasttName)); NotifyPropertyChanged(nameof(FullName)); } } }