【问题标题】:Head First C#: strange way to create a read-only propertyHead First C#:创建只读属性的奇怪方法
【发布时间】:2015-08-14 20:34:51
【问题描述】:

我正在阅读 Head First C# 书籍,但我无法弄清楚他们为什么使用以下方式来创建属性。它似乎与我在其他地方以及书中看到的惯例不一致。

我了解创建属性的模式是:

    private int myVar;

    public int MyProperty
    {
        get { return myVar; }
        set { myVar = value; }
    }

基于上述模式,我会这样编写代码:

    private decimal cost;

    public decimal Cost
    {
        get
        {   
            cost = CalculateCostOfDecorations() + (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson) * NumberOfPeople; 
            if (HealthyOption)
            {
                cost *= .95M;
            }

            return cost;
        }

    }

在书中它是这样呈现的:

    public decimal Cost
    {
        get
        {
            decimal totalCost = CalculateCostOfDecorations();
            totalCost += (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson)*NumberOfPeople;

            if (HealthyOption)
            {
                totalCost *= .95M;
            }
            return totalCost;
        }

    }

这两个代码在程序中都能正常工作。创建此类属性的最佳实践是什么?属性中的 decimal totalCostprivate 吗?如果是这样,为什么在创建属性之前没有声明它?

另外,创建两行代码有什么意义:

            decimal totalCost = CalculateCostOfDecorations();
            totalCost += (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson)*NumberOfPeople;

当你可以通过写作完成完全相同的事情时:

cost = CalculateCostOfDecorations() + (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson) * NumberOfPeople;

【问题讨论】:

  • 没有理由将cost 存储为支持字段,因为每次调用 getter 时都会重新计算它。 totalCost 是一个局部变量,它不存在于getter 的作用域之外,它临时保存计算结果直到返回值。两次使用具有相同变量名的decimal 是语法错误,并且会在您尝试编译时出现错误。
  • 感谢您的回答。另外,两次使用的“小数”是一个错字,谢谢指出。

标签: c# properties convention


【解决方案1】:

正如您所注意到的,这两个示例之间的主要区别在于,一个有一个 支持字段(这就是将 decimal cost 放在属性定义之外所做的事情)而另一个没有.

第二个示例中的 totalCost 变量根本不是字段(private 或其他),它只是 get 方法的局部变量。

两者都很好,但如果您没有将支持字段用于任何内容,那么它并不是真正需要的。至于你的第二个问题,我不知道他们为什么专门这样做,除了让变量声明更简单。

顺便说一句,两个示例都与标准 C# 实践有些不同,因为对于属性 getter 来说,这有很多逻辑。

【讨论】:

    【解决方案2】:

    两种方式都“有效”。如果你问哪种方式最好,我不会说。

    由于Cost 不是真正的字段或属性(它是计算出来的,不能由调用者设置),所以将其实现为返回值的方法会更惯用。不需要任何成员变量。

    public decimal GetCost()
    {
        var cost = CalculateCostOfDecorations() + (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson) * NumberOfPeople; 
        if (HealthyOption)
        {
            cost *= .95M;
        }
        return cost;
    }
    

    【讨论】:

    • 谢谢!我想问在这种情况下创建方法而不是属性是否更好,但这会使问题变得更长。
    • 我肯定会在这里写一个方法——尤其是因为它调用了一个方法 (CalculateCostOfDecorations())。属性应该是非常轻量级的并且不应该有副作用。
    【解决方案3】:

    属性中的小数 totalCost 是私有的吗?如果是这样,为什么 而是在创建属性之前未声明?

    它在property 内创建以限制其范围。如果您在property 上方声明了totalCost,则可以通过class 本身访问它。

    另外,创建两行代码有什么意义:

    通常,只是为了便于阅读。一个衬里很棒,直到您必须继续滚动才能完整地看到它。

    【讨论】:

      【解决方案4】:

      正如其他人所提到的,这些都不是真正地道的 C#,但是为此提供支持字段可能会导致代码稍后出现错误,例如:

      private decimal cost;
      
      public decimal Cost
      {
          get
          {   
              cost = CalculateCostOfDecorations() + (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson) * NumberOfPeople; 
              if (HealthyOption)
              {
                  cost *= .95M;
              }
      
              return cost;
          }
      
      }
      
      public decimal CalculateDiscountedCost() {
           return cost * 0.75m; //Note the deliberate mistake?
      }
      

      通过(可能不小心)在后续方法中访问支持变量,而不是访问属性,您可以轻松开发一些难以维护的代码。在这种情况下,调用时折扣成本可能是正确的,但取决于在调用 CalculateDiscountedCost 方法之前访问的公共属性 Cost 以设置支持变量。

      由于支持变量本质上是不必要的,所以最好不要它。

      【讨论】:

      • 因此,通过创建 get 方法的局部变量(如书中所述)而不是支持变量,可以避免此类错误。我理解正确吗?
      • 没错。它更多的是关于你的代码的可维护性,而不是功能上的任何真正差异。
      【解决方案5】:

      totalCost 变量不是private,它是 getter 内部的局部变量。该变量在该方法之外不存在,因此它仅在获取运行时占用内存。只要类实例存在,您的 private cost 字段就会保留在内存中。该变量仅在 getter 内部使用,因此它应该是 getter 中的本地变量,如本书所示。它没有理由成为类字段。

      创建两条线的目的是使它可以在页面上放置一条线。代码完全相同;它只是格式不同。

      【讨论】:

        【解决方案6】:

        是的,基于计算的属性根本不需要私有字段来保存值(除非您希望缓存该值以避免在后续获取时重新计算)。事实上,一种更好(至少更简洁、更容易理解)的方法是完全不使用局部变量:

        public decimal Cost
        {
            get
            {
                return (CalculateCostOfDecorations() +
                       (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson)
                         * NumberOfPeople) * HealthyOption? .95m: 1m; 
             }
        }
        

        【讨论】:

          【解决方案7】:

          您实际上应该使用 Get 方法只返回私有变量的值,因为这是要遵循的良好做法。这将使您更容易维护可能使用私有变量“以防万一”的其他功能。

          始终使用“setters”来更改变量的值,“getters”只返回它而不做任何更改。

          【讨论】:

          • 你能举个例子吗?
          【解决方案8】:

          我建议在像您这样的情况下(get 和 set 只返回或设置单个支持变量的值)使用“自动”属性,例如:

          public int MyProperty { get; set; }
          

          而且,也许,您不希望该类的外部用户访问该 setter:

          public int MyProperty { get; private set; }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-12-17
            • 2018-10-17
            • 2023-03-19
            • 2013-12-13
            • 1970-01-01
            • 1970-01-01
            • 2013-12-08
            • 1970-01-01
            相关资源
            最近更新 更多