【问题标题】:Is there a knockoutjs computed equivalent in C#?在 C# 中是否有一个 knockoutjs 计算等价物?
【发布时间】:2017-09-10 20:46:19
【问题描述】:

我经常使用knockout.js,我喜欢计算的可观察对象的概念。
计算的可观察对象被定义为其他可观察对象的函数,它依赖于其中使用的任何可观察变量.
这允许非常有趣的场景,其中所有因变量都会在一个影响其他计算变量的可观察到的变化后更新。

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

问题C# 是否有使用标准库或开源库的等效功能

【问题讨论】:

  • var compute = () => num1 + num2;?
  • 在本机上,只有一种内置类型/接口来定位这种 ioc,如 observableCollection、INotifyPropertyChanged 等……但据我所知,请注意这样的专业。但这听起来像是 AOP 模式的一种特殊情况(Postsharp、NConcern、Fody、Castle 等)

标签: javascript c# knockout.js


【解决方案1】:

答案:是的,有。

接口INotifyPropertyChanged 正在这样做,它位于System.ComponentModel 命名空间中。
该接口包含一个PropertyChanged事件,该事件会在属性改变时触发。

C# 4 及以下示例

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

这是对两个整数求和的非常简单的示例
我们有FirstNumber 属性,(我们可以将其视为可观察到的淘汰赛)
我们还有SecondNumber 属性(我们可以将其视为 Knockout observable)
并且我们有 Sum 属性(我们可以将其视为 Knockout Computed)。

现在,每次我们更改 FirstNumberSecondNumber(通过调用其相应的 set 函数)时,我们都会通知所有订阅者这些属性(通过调用 OnPropertyChanged 方法完成)

我们还为Sum 属性调用OnPropertyChanged,以通知该属性的订阅者该属性的值已更改。

注意这是使用 WPF + MVVM 模式时非常常见的模式。

在使用 C# 5.0C# 6.0 时,您可以从它们的新功能中受益,让代码变得更简单

C# 5.0 示例

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

这里有两个变化

  1. protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null),所以通过把这个属性放在方法的参数之前,编译器会自动知道调用这个方法的属性的名称,而不需要手动传递属性名称,所以我们可以编写如下语句。
  2. OnPropertyChanged(); 代表第二次修改。

注意:CallerMemberName 属性存在于 System.Runtime.CompilerServices 命名空间中

C# 6.0 示例

使用 C# 6.0,我们可以简化 OnPropertyChanged 方法的实现。

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

更新
回应以下评论:

有趣!但是在这里你必须自己管理你的依赖。您必须触发 Sum 的属性更改。在淘汰赛中,它会自行确定哪些属性将触发在计算上更改的属性。有什么办法吗?

我想你可以有两个选择(至少)

  1. PropertyChanged library on GitHub.
    这个库的描述是:

    在编译时将 INotifyPropertyChanged 代码注入属性

    这是从Nuget下载库后的新代码

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

    2.PostSharp Library


干杯!。

【讨论】:

  • 有趣!但是在这里你必须自己管理你的依赖。您必须触发 Sum 的属性更改。在淘汰赛中,它会自行确定哪些属性将触发在计算上更改的属性。有什么办法吗?
  • 你是对的。你必须以这种方式管理你自己的依赖。实际上我没有其他方法可以自动执行此操作,但也许我会搜索
  • @EtienneT 我根据您的评论更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多