Есть ли какое-либо преимущество использования оператора nameof вместо CallerMemberNameAttribute для уведомления об изменениях свойств in.NET 4.5.3?

С появлением .NET 4.5.3 разработчики WPF теперь имеют три (или более) способа уведомления INotifyPropertyChanged интерфейс изменения свойств. В принципе, мой вопрос какой из двух методов введен from.NET 4.5 и далее-это более эффективный способ уведомления об изменениях свойств и имеет ли какой-либо способ преимущества при использовании в WPF?

фон

для тех, кто не так хорошо знаком с этой темой, вот основные три метода. Первый-это оригинальный, более подверженный ошибкам метод простой передачи строки:

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));
    }
}

второй метод был представлен в .NET 4.5;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));
    }
}

третий и самый последний метод был (или скоро будет) представлен в C#6.0 как часть .NET 4.5.3;nameof оператор:

public string TestValue
{
    get { return testValue; }
    set { testValue = value; NotifyPropertyChanged(nameof(TestValue)); }
}

protected virtual void NotifyPropertyChanged(string propertyName)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

мое собственное предположение было бы, что исходный, более подверженный ошибкам метод просто передает строку было бы наиболее эффективным, поскольку я могу только представить, что два других метода используют некоторую форму отражения. Тем не менее, я очень хочу узнать, какой из двух других методов более эффективен и будет ли на самом деле какая-либо разница между использованием и nameof оператор в контексте WPF.

2 ответов


об эффективности: использование строки напрямую,CallerMemberNameAttribute, nameof все точно такие же, так как строка вводится компилятором во время компиляции. Нет никакого отражения.

мы можем видеть, что с помощью TryRoslyn, что производит это 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));
    }
}

и это 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));
    }
}

так как во время выполнения Все параметры просто string нет никаких проблем с WPF контекст.

удобство: CallerMemberNameAttribute требует, чтобы у вас был дополнительный параметр while nameof а не nameof требуется указать свойство while CallerMemberNameAttribute нет.

я предсказываю, что nameof оказалось бы настолько популярным, что было бы намного проще использовать его вместо этого.


на CallerMemberNameAttribute может использоваться только для вызываемой функции get имя вызывающей функции.

на nameof оператор выходит далеко за его пределы. Он может быть использован в любом месте.

Если вы хотите рассуждать об этом только в области привязки данных WPF, возьмите этот пример:

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));
        }
   }
}