Почему для метода SetProperty () в INotifyPropertyChanged требуется аргумент ref? - PullRequest
1 голос
/ 14 мая 2019

Учитывая, что реализация INotifyPropertyChanged обычно выглядит следующим образом:

    public class Observable : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void SetProperty<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
        {
            if (Equals(storage, value))
            {
                return;
            }

            storage = value;
            OnPropertyChanged(propertyName);
        }

        protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

Почему для метода SetProperty требуется аргумент ref?Вряд ли есть шанс, что что-то еще, кроме поля класса, будет передано методу, так что он всегда должен быть ссылочным типом?

Примечание: я задаю этот вопрос, потому что я хочу использовать этот метод с элементами, перечисленными черезцикл foreach, который не работает с ключевым словом ref.

1 Ответ

4 голосов
/ 14 мая 2019

Предполагается, что вы передадите поле по ссылке, а также новое значение.

Если бы это был не параметр ref, вы бы передали значение поля ... в этот момент это утверждение:

storage = value;

... будет бессмысленным.Это изменило бы значение параметра , но не изменило бы поле .

Вот полный пример, демонстрирующий разницу:

using System;

class Program
{
    static string field;

    static void Main()
    {
        field = "initial value";
        Console.WriteLine($"Before Modify1: {field}");

        Modify1(field, "new value for Modify1");
        Console.WriteLine($"After Modify1: {field}");

        Modify2(ref field, "new value for Modify2");
        Console.WriteLine($"After Modify2: {field}");
    }

    static void Modify1(string storage, string value)
    {
        // This only changes the parameter
        storage = value; 
    }

    static void Modify2(ref string storage, string value)
    {
        // This changes the variable that's been passed by reference,
        // e.g. a field
        storage = value;
    }        
}

Вывод:

Before Modify1: initial value
After Modify1: initial value
After Modify2: new value for Modify2

Как видите, Modify1 (без ref) вообще не изменил поле, тогда как Modify2 сделал.

...