简体   繁体   English

Head First C#:创建只读属性的奇怪方法

[英]Head First C#: strange way to create a read-only property

I am going through the Head First C# book and I can't figure out why they used the following way to create a property. 我正在阅读Head First C#书,我无法弄清楚为什么他们使用以下方式创建一个属性。 It just seems inconsistent with the convention I'm seeing everywhere else and in the book itself too. 它似乎与我在其他地方看到的惯例和书本身也不一致。

I understand that the pattern for creating properties is: 我知道创建属性的模式是:

    private int myVar;

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

Based on the above pattern I would have written my code like this: 根据上面的模式,我会写这样的代码:

    private decimal cost;

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

            return cost;
        }

    }

In the book it is presented like the following: 在书中,它呈现如下:

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

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

    }

Both codes work just fine in the program. 这两个代码在程序中都运行良好。 What is the best practice to create such properties? 创建此类属性的最佳做法是什么? Is the decimal totalCost inside the property private ? 属性中的十进制totalCost私有的吗? If so, why is it not declared before creating the property instead? 如果是这样,为什么在创建属性之前没有声明它?

Also, what is the point of creating two lines of code: 另外,创建两行代码有什么意义:

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

when you can accomplish the exact same thing by writing: 当你通过写作完成同样的事情时:

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

The primary difference between the two samples is, as you have noticed, that one has a backing field (which is what putting decimal cost outside the property definition does) and the other doesn't. 正如您所注意到的,两个样本之间的主要区别在于,有一个支持字段 (这是将decimal cost放在属性定义之外的情况)而另一个没有。

The totalCost variable in the second sample isn't a field at all ( private or otherwise), it is simply a variable local to the get method. 第二个示例中的totalCost变量根本不是字段( private或其他),它只是get方法的本地变量。

Both are fine, though if you aren't using the backing field for anything, its not really necessary to have. 两者都很好,但如果你没有使用支持领域的任何东西,它不是真的有必要。 As to your second question, I have no idea why they specifically did it that way, other than to make the variable declaration simpler. 关于你的第二个问题,我不知道为什么他们特意这样做,除了使变量声明更简单。

As an aside, both samples are a bit off from standard C# practice, as thats an awful lot of logic for a property getter. 顺便说一下, 这两个示例都与标准C#实践有点不同,因为这对于属性获取者来说是非常多的逻辑。

Both ways "work." 两种方式都“有效”。 If you're asking which way is best, I'd say neither. 如果你问哪条路最好,我也不会说。

Since Cost isn't really a field or property (it is something that is computed, and cannot be set by the caller), it would be more idiomatic to implement as a method which returns a value. 由于Cost实际上不是一个字段或属性(它是计算的东西,并且不能由调用者设置),因此实现它作为返回值的方法更为惯用。 No member variable should be needed. 不需要成员变量。

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

Is the decimal totalCost inside the property private? 属性中的十进制totalCost是私有的吗? If so, why is it not declared before creating the property instead? 如果是这样,为什么在创建属性之前没有声明它?

It is created inside the property to limit its scope. 它在property内创建以限制其范围。 If you declared totalCost above the property , it would be accessible throughout the class itself. 如果您在property上方声明了totalCost ,那么整个class本身都可以访问它。

Also, what is the point of creating two lines of code: 另外,创建两行代码有什么意义:

Usually, just for readability. 通常,只是为了可读性。 One liners are great until you have to keep scrolling to see it in its entirety. 一个衬垫很棒,直到你必须继续滚动才能完整地看到它。

As mentioned by others, neither of these is really idiomatic C#, however having the backing field for this could lead to errors later on in the code, eg: 正如其他人所提到的,这些都不是真正惯用的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?
}

By (possibly accidentally) accessing the backing variable in the subsequent method, rather than the property you could easily develop some hard to maintain code. 通过(可能意外地)访问后续方法中的后备变量,而不是属性,您可以轻松地开发一些难以维护的代码。 In this case, the discounted cost may be right when called, but would depend on the public propery Cost being accessed prior to calling the CalculateDiscountedCost method in order to set the backing variable. 在这种情况下,折扣成本在调用时可能是正确的,但取决于在调用CalculateDiscountedCost方法之前访问的公共Cost ,以便设置后备变量。

As the backing variable is essentially unnecessary, it would be be better to do without it. 由于支持变量基本上是不必要的,所以没有它会更好。

The totalCost variable is not private , it's local variable inside of the getter. totalCost变量不是private ,它是getter中的局部变量。 The variable does not exist outside of that method so it only takes up memory while the getting is running. 变量在该方法之外不存在,因此它只在获取运行时占用内存。 Your private cost field will stay in memory as long as the class instance does. 只要类实例执行,您的private cost字段将保留在内存中。 The variable is only ever used inside of the getter so it should be a local in the getter as the book shows. 变量只在getter中使用,所以它应该是getter中的本地变量,如本书所示。 There is no reason for it to be a class field. 它没有理由成为一个类领域。

The point of creating two lines is so that it can fit a single line on the page. 创建两行的关键是它可以在页面上放置一行。 The code is exactly the same; 代码完全一样; it is just formatted differently. 它的格式不同。

yes, properties that are based on calculations do not require a private field to hold the value at all (unless you wish to cache the value to avoid recalculation on follow gets). 是的,基于计算的属性根本不需要私有字段来保存值(除非您希望缓存该值以避免在后续获取时重新计算)。 in fact an even better (at least terser and easier to follow) way is to do it with no local variables at all: 事实上,更好的方法(至少是更简洁,更容易理解)的方法是在没有局部变量的情况下做到这一点:

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

You should actually use the Get method to only return the value of the private variable, as this is the good practice to follow. 实际上,你应该使用Get方法只返回私有变量的值,因为这是一个很好的做法 It will make it easier for you to maintain other functions that may use the private variable 'just in case'. 它将使您更容易维护可能使用私有变量的其他函数“以防万一”。

Always use "setters" to change the value of the variable, "getters" to just return it without any changes. 始终使用“setter”来更改变量的值,“getters”只返回它而不做任何更改。

I would suggest that in cases like you have (where the get and set just return or set the value of the single backing variable) that you use "automatic" properties, such as this: 我建议在你喜欢的情况下(get和set只返回或设置单个支持变量的值)你使用“自动”属性,例如:

public int MyProperty { get; set; }

And, perhaps, you don't want external users of the class to have access to that setter: 而且,也许,您不希望该类的外部用户有权访问该setter:

public int MyProperty { get; private set; }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM