【问题标题】:.NET logic in setter and a backing fieldsetter 和支持字段中的 .NET 逻辑
【发布时间】:2015-09-01 09:12:51
【问题描述】:

我有两个属性,其中后一个 (CalulcatedValue) 必须在第一个 (FXRate) 更改时更新。

我可以通过设置CalulcatedValue ReadOnly 并从FXRate setter 调用OnPropertyChanged("CalculatedValue") 来实现这一点。

public double FXRate {
    get { return _fXRate; }
    set {
        Set(_fXRate, value, "FXRate");
        OnPropertyChanged("CaluclatedValue");
    }
}

public float CalculatedValue  
{
    get { return FXRate * SomeOtherValue;}
}

但我知道CalulcatedValue 属性会被多次调用(用于多个LINQ 查询等)。我正在考虑 getter 应该非常快地返回值,并计划为其放置一个支持字段。

public double FXRate 
{
    get { return _fXRate;}
    set {
        Set(_fXRate, value, "FXRate");
        CalculatedValue = 0; //how to set CalculatedValue since it's setter is calculating it with its logic, i.e. the value parameter is not needed ?
    }
}
private double _fXRate;

public float CalculatedValue  
{
    get { return _calculatedValue; }
    set {
        __calculatedValue = FXRate * SomeOtherValue); //consider this line takes some effort to be calculated -> instead of SomeOtherValue there might be pretty complex logic here to get the result
        OnPropertyChanged("CalculatedValue");
    }
}
private float _calculatedValue;

CalulcatedValue 现在应该如何设置?它不需要传递任何值参数,因为逻辑在 setter 内部。线

计算值=0

现在是愚蠢的事情发生的地方。

【问题讨论】:

  • 有一个不使用value 的setter 是典型的代码异味。只是没有。

标签: c# .net setter


【解决方案1】:

如果您需要INotifyPropertyChanged 通知,请将其添加到您的FXRate 属性(和/或任何可能更改CalculatedValue 值的属性),并在那里进行计算:

private double _fXRate;
private float _calculatedValue;

public double FXRate 
{
  get { return _fXRate;}
  set {
      Set(_fXRate, value, "FXRate");
      _calculatedValue = _fxRate * SomeOtherValue;
      // this will update any control depending on the `CalculatedValue` notification
      OnPropertyChanged("CalculatedValue");
  }
}

public float CalculatedValue  
{
  get { _calculatedValue; }
}

或者,如果您想将计算推迟到第一次读取(因为您将多次更新您的 FxRate 或在实际读取 CalculatedValue 之前进行某些操作),您可以执行以下操作:

private double _fXRate;
private float _calculatedValue;
private bool _calculatedValueIsDirty = true;

public double FXRate 
{
  get { return _fXRate;}
  set {
      Set(_fXRate, value, "FXRate");
      _calculatedValueIsDirty = true;
      OnPropertyChanged("CalculatedValue");
  }
}

public float CalculatedValue  
{
  get { 
      if(_calculatedValueIsDirty) {
        _calculatedValue = _fxRate * SomeOtherValue;
        _calculatedValueIsDirty = false;
      }
      return _calculatedValue;
  }
}

CalculatedValue 的后续读取将很快返回,除非预先计算的值再次变脏(通过更改 FXRate

PS:如果有任何类似于多线程的东西,请在必要时应用锁:-)

【讨论】:

    【解决方案2】:

    由于 CalculatedValue 是其他属性的计算结果,它不应该有一个 setter。如果您出于性能原因不想在 get 上进行计算,请按如下方式预先计算:

    public double FXRate 
    {
       get { return _fXRate;}
       set 
       {
            Set(_fXRate, value, "FXRate");
            CalculateStuff();
       }
    }
    private double _fXRate;
    
    public float CalculatedValue  
    {
        get { return _calculatedValue; }
    }
    
    private void CalculateStuff()
    {
        // This calculation is private to the class so I see no reason to not use the fields..
    
        _calculatedValue = _fXRate * SomeOtherValue; //consider this line takes some effort to be calculated -> instead of SomeOtherValue there might be pretty complex logic here to get the result
        OnPropertyChanged("CalculatedValue");
    }
    
    private float _calculatedValue;
    

    【讨论】:

      【解决方案3】:

      您根本不需要二传手。你只需要一个 getter 属性:

      public float CalculatedValue  
      {
          get { return FXRate * SomeOtherValue; }
      }
      

      如果您使用的是 C# 6:

      public float CalculatedValue => FXRate * SomeOtherValue;
      

      编辑:

      由于计算的值是耗时的,也许 getter 应该有更多的“牛肉”,因为你有一个扩展的算法来决定是否应该计算属性。

      private float calculatedValue;
      public float CalculatedValue  
      {
          get 
          { 
              if (ShouldRecalculate())
              {
                  calculatedValue = DoHeavyCalculation();
              }
              return calculatedValue;
          }
      }
      

      【讨论】:

      • 这正是 OP 想要避免的(因为计算可能需要一些时间)。
      • 我编辑了原始帖子以澄清。这正是我想避免的,因为计算量很大。
      • 如果计算很耗时,又想快速返回,这根本不应该是属性。
      • @user2143213 当访问您的计算属性时,您期望会发生什么?
      • @user2143213 进行或不进行计算的决策在哪里?也许您想扩展 getter 以获得更复杂的逻辑来确定何时计算值。
      【解决方案4】:

      好的,所以您的示例计算是一个非常便宜的计算,如果放入缓冲变量中不会产生明显的改进。为了这个答案,我假设您实际进行的计算要复杂得多且昂贵得多。

      现在对于属性来说,确保它们在执行时花费相同的时间并且没有很多不相关的副作用总是一件好事。这样你的代码就很简单了。

      我认为你已经非常接近你真正想要的了。我如何避免隐藏在您的财产设置器中的任何不可读的黑客攻击。此外,我强烈建议在这里使用私人设置器,以避免外部的任何人弄乱您的值。

      我会选择这样的:

      public double FXRate 
      {
          get { return _fXRate;}
          set {
              Set(_fXRate, value, "FXRate");
              CalculatedValue = value * SomeOtherValue;
              /* The calculation is completely done here. Using the value parameter because 
               * it is local and has slightly less overhead then accessing the class variable
               * or the property we are just setting. It is in general a good idea to avoid
               * reading the property in the setter. */
          }
      }
      private double _fXRate;
      
      public float CalculatedValue  
      {
          get { return _calculatedValue; }
          private set {
              Set(_calculatedValue, value, "CalculatedValue");
          }
      }
      private float _calculatedValue;
      

      这样您就拥有了一个非常干净的属性模型,并且计算发生在实际完成相关更改的地方。此时,您还可以检查该值是否实际更改,并跳过更新昂贵的计算值,以防不需要。

      【讨论】:

        猜你喜欢
        • 2011-01-17
        • 2021-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-26
        • 1970-01-01
        • 2021-07-13
        相关资源
        最近更新 更多