2

I use knockout.js a lot and I love the concept of the computed observable.
The idea that a computed observable is defined as a function of other observable and it takes a dependence on any observable variable used inside of it.
This allow for very interesting scenarios where all your dependent variables update once a single observable change that impact other computed variables.

http://knockoutjs.com/documentation/computedObservables.html

Question :Does C# have something equivalent using either standard libraries or an open source library?

Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
EtienneT
  • 5,045
  • 6
  • 36
  • 39
  • `var compute = () => num1 + num2;`? – itsme86 Apr 14 '17 at 15:08
  • natively, there is only kind of builtin types/interfaces to orient this kind of ioc like observableCollection, INotifyPropertyChanged, etc... but noting specialized like this at my knowledge. But it sound like kind of specific case of AOP pattern (Postsharp, NConcern, Fody, Castle, etc...) – Tony THONG Apr 14 '17 at 15:10

1 Answers1

3

Answer : Yes, There is.

The Interface INotifyPropertyChanged is doing that, It is in the System.ComponentModel namespace.
This interface contains an PropertyChanged event, which will trigger when the property is changed.

C# 4 and below Example

public class DataCS4 : INotifyPropertyChanged
{
    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion

    // Represent an Observable
    private int firstNumber;
    public int FirstNumber
    {
        get { return firstNumber; }
        set
        {
            if (value == firstNumber)
                return;

            this.firstNumber = value;
            OnPropertyChanged("FirstNumber");
            OnPropertyChanged("Sum");
        }
    }

    // Represent an Observable
    private int secondNumber;
    public int SecondNumber
    {
        get { return secondNumber; }
        set
        {
            if (value == secondNumber)
                return;

            this.secondNumber = value;
            OnPropertyChanged("SecondNumber");
            OnPropertyChanged("Sum");
        }
    }

    // Represent Computed
    public int Sum { get { return FirstNumber + SecondNumber; } }
}

This is very simple example to Sum two integers
We have FirstNumber property, (which we could consider as Knockout observable)
We have also SecondNumber property (which we could consider as Knockout observable)
and We have Sum property (which we could consider as Knockout Computed).

Now every time we change either FirstNumber or SecondNumber (by calling their corresponding set functions), we are notifying all subscribers for those properties (this done by calling the OnPropertyChanged method)

Also we are calling the OnPropertyChanged for the Sum property to notify the subscribers for that property that the value of this property has changed.

NOTE This is very common pattern when using WPF + MVVM pattern.

When using C# 5.0 or C# 6.0, you could benefits from their new features to make the code little easier

C# 5.0 Example

public class DataCS5 : INotifyPropertyChanged
{
    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

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

    #endregion

    // Represent an Observable
    private int firstNumber;
    public int FirstNumber
    {
        get { return firstNumber; }
        set
        {
            if (value == firstNumber)
                return;

            this.firstNumber = value;
            OnPropertyChanged();
            OnPropertyChanged("Sum");
        }
    }

    // Represent an Observable
    private int secondNumber;
    public int SecondNumber
    {
        get { return secondNumber; }
        set
        {
            if (value == secondNumber)
                return;

            this.secondNumber = value;
            OnPropertyChanged();
            OnPropertyChanged("Sum");
        }
    }


    // Represent Computed
    public int Sum { get { return FirstNumber + SecondNumber; } }
}

there is two changes here

  1. protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null), So by putting this attribute before the parameter of the method, The compiler will know the name of the property which called this method automatiilcay, without passing the property name manually, So we can write the following statement.
  2. OnPropertyChanged(); which represent the second modification.

Note: CallerMemberName attribute exists in the System.Runtime.CompilerServices namespace

C# 6.0 Example

With C# 6.0 we could simplify the implemenation of the OnPropertyChanged method.

public class DataCS6 : INotifyPropertyChanged
{
    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    // C# 6.0
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion

    // Represent an Observable
    private int firstNumber;
    public int FirstNumber
    {
        get { return firstNumber; }
        set
        {
            if (value == firstNumber)
                return;

            this.firstNumber = value;
            OnPropertyChanged();
            OnPropertyChanged("Sum");
        }
    }

    // Represent an Observable
    private int secondNumber;
    public int SecondNumber
    {
        get { return secondNumber; }
        set
        {
            if (value == secondNumber)
                return;

            this.secondNumber = value;
            OnPropertyChanged();
            OnPropertyChanged("Sum");
        }
    }

    // Represent Computed
    public int Sum => FirstNumber + SecondNumber;
}

Reference

Update
Responding to the following comment :

Interesting! But here you have to manage your dependencies yourself. You have to trigger a property changed for Sum. In knockout it figures out by itself which properties shall trigger a property changed on the computed. Any way of doing that?

I think you could you have two options (at least)

  1. PropertyChanged library on GitHub.
    The description of this library is :

    Injects INotifyPropertyChanged code into properties at compile time

    here is the new code after you download the library from the Nuget

    [PropertyChanged.ImplementPropertyChanged]
    public class Data
    {
        public int FirstNumber { get; set; }
    
        public int SecondNumber { get; set; }
    
        public int Sum => SecondNumber + FirstNumber;
    }
    

    2.PostSharp Library


Cheers !.

Community
  • 1
  • 1
Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
  • Interesting! But here you have to manage your dependencies yourself. You have to trigger a property changed for Sum. In knockout it figures out by itself which properties shall trigger a property changed on the computed. Any way of doing that? – EtienneT Apr 18 '17 at 19:36
  • You are right. You have to manage dependency your self in this way. Actually i don't have another way in my mind to do that automatically but maybe I will serach – Hakan Fıstık Apr 18 '17 at 20:00
  • @EtienneT I updated my answer according to your comment. – Hakan Fıstık Apr 19 '17 at 07:24