13. May 2012 · 4 comments · Categories: .NET 4.5, C#

Новый C# принес всего три новые фичи. Основаная – async/await уже достаточно разрекламирована. Вторая – изменение области видимости переменной цикла в foreach – скорее исправление ошибки в дизайне языка, чем полноценная фича. Третье изменение, которое затронуло непосредственно сам язык – это появление аттрибутов Caller Info.

Аттрибуты Caller Info – это три аттрибута: CallerFilePathAttribute, CallerLineNumberAttribute и CallerMemberNameAttribute. Их можно применить только к необязательным параметрам. Встретив вызов метода с одим из этих аттрибутов, компилятор попытается подставить информацию о вызывающем методе вместо значения параметра по умолчанию.

Есть два прямых применения этих аттрибутов. Первое – помощь в логгировании и трассировке. В примерах MSDN показано именно применение Caller Info вместе с System.Diagnostics.Trace:

Второе, и, наверное, более интересное примение – это упрощение реализации интерфейса INotifyPropertyChanged.

Стандартная реализация INotifyPropertyChanged в C# 4.0 выглядит так:

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    public string CustomerName
    {
        get
        {
            return this.customerNameValue;
        }

        set
        {
            if (value != this.customerNameValue)
            {
                this.customerNameValue = value;
                NotifyPropertyChanged("CustomerName");
            }
        }
    }

В C# 5.0 она упрощается до:

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public string CustomerName
    {
        get
        {
            return this.customerNameValue;
        }

        set
        {
            if (value != this.customerNameValue)
            {
                this.customerNameValue = value;
                NotifyPropertyChanged();
            }
        }
    }   

Без явного упоминания свойства по имени шанс поломать что-то при рефакторинге немного сокращается.

Да, ReSharper и раньше старался менять строковые константы при переименованиях свойств. И было несколько решений с лямбда-выражениями, вида NotifyPropertyChanged(() => this.CustomerName). Но встроенное в язык решение все-таки приятнее, чем обходные пути.

4 Comments

  1. изменение области видимости переменной цикла в foreach – скорее исправление ошибки в дизайне языка, чем полноценная фича.

    Просто в спецификации не было оговорено, где будет объявлена переменная и сделали по образу for.

    Reply

    • В спецификации как раз было оговорено, где-то в 8.8.4. Подправили и компилятор, и спецификацию :)

      Reply

  2. >Но встроенное в язык решение все-таки приятнее, чем обходные пути.

    Еще есть решение с ручным потрошением StackTrace.

    Reply

    • Да, но оно медленное. Даже медленее, чем вариант с лямбдами. Не настолько, чтобы им не пользоваться, но многие сильно загоняются по поводу скорости базовых вещей :)

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>