Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating an Observable<T> class: overloading = operator?

I'm trying to create a class that holds a value, will raise an event whenever the value changes, and will implicitly convert to and from the type it holds.

My goal is that I should be able to create an Observable property of a class, and have another class (including WPF controls) be able to read and write to it as if it were a regular string. Other classes could maintain a reference to it as an Observable, or even expose it as its own property without having to create new events.

Here is what I have so far:

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

The problem is that the "=" operator is complaining that it cannot be overloaded. I guess that makes sense, since it could lead to all sorts of strange behaviors. Is there another way to achieve what I'm going for?

EDIT: Here is how I have decided to implement this. Let me know if there are any better suggestions :)

I realized that this case should really be handled by the property that holds the Observable. Here is an example of what I would like to do:

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

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

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

Of course, that doesn't compile because Property is defined twice. Here's the somewhat hackish workaround that I'm thinking of defining an implicit conversion the other way (as many of you have suggested):

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

and using that to call the property's setter:

public Observable<string> Property
{
    get { return _property; }
    set { _property.Value = value.Value; }
}
like image 200
hypehuman Avatar asked Dec 21 '12 19:12

hypehuman


2 Answers

You can overload the implicit operator.

public static operator implicit string(YourObject object)

and to go the other way

public static operator implicit YourObject(string s)

Be aware, though, this is very dangerous. It can lead to the consumers of the class to do some things you never thought of; and some behavior that doesn't make sense.

like image 174
John Kraft Avatar answered Sep 22 '22 22:09

John Kraft


If you look at the Overloadable Operators in C#, you'll see that:

Assignment operators cannot be overloaded, but +=, for example, is evaluated using +, which can be overloaded.

You can make an implicit operator Observable<T>(T value), however, which would allow you to implicitly convert from T to Observable<T>.

That being said, I would not recommend this. I would make the assignment explicit, as this would require creating a new Observable<T> each time it was called, which is going to cause problems with your event handlers, as each assignment will create a new object instance.

like image 20
Reed Copsey Avatar answered Sep 24 '22 22:09

Reed Copsey