Создание класса Observable‹T›: перегрузка = оператор?

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

Моя цель состоит в том, чтобы я мог создать свойство Observable класса, а другой класс (включая элементы управления WPF) мог читать и записывать его, как если бы это была обычная строка. Другие классы могут поддерживать ссылку на него как на Observable или даже предоставлять его как собственное свойство без необходимости создавать новые события.

Вот что у меня есть до сих пор:

using System;
using System.ComponentModel;

namespace SATS.Utilities
{
    public class Observable<T>
    {
        private T mValue;

        public event EventHandler ValueChanged;
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyValueChanged()
        {
            if (ValueChanged != null)
            {
                ValueChanged(this, new EventArgs());
            }
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Value"));
            }
        }

        public T Value
        {
            get
            {
                return mValue;
            }
            set
            {
                SetValueSilently(value);
                NotifyValueChanged();
            }
        }

        public void SetValueSilently(T value)
        {
            mValue = value;
        }

        public static implicit operator T(Observable<T> observable)
        {
            return observable.Value;
        }

        public static T operator =(Observable<T> observable, T value) // Doesn't compile!
        {
            observable.Value = value;
            return value;
        }
    }
}

Проблема в том, что оператор "=" жалуется, что не может быть перегружен. Я думаю, это имеет смысл, так как это может привести ко всем видам странного поведения. Есть ли другой способ добиться того, к чему я иду?

РЕДАКТИРОВАТЬ: Вот как я решил реализовать это. Дайте мне знать, если есть лучшие предложения :)

Я понял, что этот случай действительно должен обрабатываться свойством, которое содержит Observable. Вот пример того, что я хотел бы сделать:

public class A
{
    private readonly Observable<string> _property;

    public Observable<string> Property
    {
        get { return _property; }
    }

    public string Property
    {
        set { _property.Value = value; }
    }
}

Конечно, это не компилируется, потому что свойство определено дважды. Вот несколько хакерский обходной путь, который я думаю об определении неявного преобразования другим способом (как многие из вас предлагали):

public static implicit operator Observable<T>(T value)
{
    var result = new Observable<T>();
    result.SetValueSilently(value);
    return result;
}

и используя это для вызова установщика свойства:

public Observable<string> Property
{
    get { return _property; }
    set { _property.Value = value.Value; }
}

person hypehuman    schedule 21.12.2012    source источник


Ответы (3)


Вы можете перегрузить оператор implicit.

public static operator implicit string(YourObject object)

и пойти другим путем

public static operator implicit YourObject(string s)

Имейте в виду, однако, что это очень опасно. Это может привести к тому, что потребители класса сделают некоторые вещи, о которых вы никогда не думали; и некоторое поведение, которое не имеет смысла.

person John Kraft    schedule 21.12.2012
comment
Я думал об этом, но вот проблема. Допустим, я делаю следующее: [Observable‹string› A = new Observable‹string›(); Наблюдаемая‹строка› B = A; A = hi;] Теперь A и B не синхронизированы, потому что вместо установки значения A мы заменили его новым объектом Observable. - person hypehuman; 21.12.2012
comment
На самом деле, я решил, что это действительно сработает для меня. Я отредактирую свой вопрос, чтобы объяснить, как это сделать. - person hypehuman; 21.12.2012

Если вы посмотрите на Перегружаемые операторы в C#, вы увидите, что:

Операторы присваивания не могут быть перегружены, но +=, например, оценивается с помощью +, который может быть перегружен.

Однако вы можете сделать implicit operator Observable<T>(T value), что позволит вам неявно преобразовать T в Observable<T>.

При этом я бы не рекомендовал это. Я бы сделал присваивание явным, так как это потребовало бы создания нового Observable<T> при каждом его вызове, что вызовет проблемы с вашими обработчиками событий, поскольку каждое присваивание будет создавать новый экземпляр объекта.

person Reed Copsey    schedule 21.12.2012

Добавьте еще одно неявное преобразование в следующих строках:

public static implicit operator Observable<T>(T value)
{
    return new Observable<T>{Value = value};
}
person SWeko    schedule 21.12.2012