Użyteczne atrybuty z System.Runtime.CompilerServices.

.Net Framework w wersji 4.5 oferuje nam dość przydatną przestrzeń nazw, System.Runtime.CompilerServices. Mnogość klas, atrybutów może przytłoczyć, ja z tego miejsca chciałem pokazać moim zdaniem najprzydatniejszy atrybut, oraz dwójkę jego mniej przydatnych braci.

CallerMemberName, to atrybut, który potrafi rozpoznać, kto go wywoływał. Tzn jaka metoda czy propertka obiektu wywołującego została użyta w danym momencie.

Zastosowanie? Najszybciej do głowy przychodzi WPF i konieczność implementowania interfejsu INotifyPropertyChanged, gdzie w „klasycznej” wersji podawaliśmy ręcznie nazwę propertki, której wartość była aktualizowana.

1. Wersja „prosta do bólu”

        private int number;
        public int Number
        {
            get { return number; }
            set
            {
                number = value;
                OnPropertyChanged("Number");
            }
        }

        void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

2. Zastosowanie CallerMemberName

        private int number;
        public int Number
        {
            get { return number; }
            set
            {
                number = value;
                OnPropertyChanged();
            }
        }

        void OnPropertyChanged([CallerMemberName]string propertyName = null)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

Znacznie ładniej? Tak, należy zauważyć, że zmienna oznaczona atrybutem CallerMemberName musi mieć swoją wartość domyślną, inaczej kompilator wyrzuci nam błąd.

3. Inne przykłady

        static void Test()
        {
            Test2();
        }

        static void Test2([CallerMemberName] string name = null, [CallerFilePath] string path = null, [CallerLineNumber] int lineNumber = 0)
        {
            Console.WriteLine(name);
            Console.WriteLine(path);
            Console.WriteLine(lineNumber);
        }

        static void Main(string[] args)
        {
            Test();
        }

tutaj zostały przemycone dwa pozostałe ciekawe atrybuty: CallerFilePath oraz CallerLineNumber. Zastosowanie? Mi jako pierwsze do głowy przychodzi logowanie błędów 🙂

Podsumowując, atrybut CallerMemberName jest ciekawą nowością w .Net 4.5, który może znacznie ułatwić i uodpornić na proste błędy aplikacje korzystające z INotifyPropertyChanged.