成员变量和成员属性之间的区别?

时间:2010-02-17 17:41:57

标签: c# oop

在某些情况下,我在我的类顶部声明成员变量,然后声明一个属性来访问或设置该成员变量,但我问自己,如果该变量只是被访问,那么该属性是否必要从类中设置而不是在其他地方设置,因此使用属性访问和设置成员变量的优势是什么,而不是直接将其直接添加到成员变量本身。这是一个例子:

public class Car
{

    int speed; //Is this sufficient enough if Car will only set and get it.

    public Car(int initialSpeed)
    {
        speed = initialSpeed;
    }

    //Is this actually necessary, is it only for setting and getting the member
        //variable or does it add some benefit to it, such as caching and if so,
        //how does caching work with properties.
    public int Speed 
    {
        get{return speed;}
        set{speed = value;}
    }

        //Which is better?
        public void MultiplySpeed(int multiply)
        {
            speed = speed * multiply; //Line 1
            this.Speed = this.Speed * multiply; //Line 2

            //Change speed value many times
            speed = speed + speed + speed;
            speed = speed * speed;
            speed = speed / 3;
            speed = speed - 4;

        }
}

在上面,如果我没有设置Speed属性并获得变速,我决定将int speed更改为int spd,我将不得不将速度更改为spd,但是,如果我使用诸如Speed之类的属性来设置和获取速度,我将只需要在属性的get和set中将spd的速度更改为spd,所以在我的MutilplySpeed方法中,像上面这样的东西.Speed = this.Speed + this .Speed + this.Speed不会破坏。

8 个答案:

答案 0 :(得分:23)

如果变量是private,我通常不会为它创建属性。如果它以任何方式暴露在类型之外,我总是通过一个属性暴露它:出于不同的原因:

  • 今天可能没有必要,但如果有必要,以后会发生重大变化
  • 数据绑定仅适用于属性,而不适用于字段(我认为,不是大型数据绑定用户)
  • 允许在访问值时插入验证,记录,断点

此外,如果字段是通过属性公开的,我总是通过属性访问它,即使在类中也是如此。

<强>更新
为了回应您更新的代码示例:在此处代码设计需要考虑许多事项。

  • 可读性与速度
  • “原子性”
  • 其他副作用

一个典型的建议(我发现非常好)是“为了清晰起见,为性能测试”。这意味着当你编写代码时,首先要考虑的是代码在查看代码时是否清楚。这通常(但并非总是)比代码的原始速度更重要。在确定获得它的位置时写入速度优化。访问一个属性比直接读取字段要慢一些,但在大多数情况下,差异可以忽略不计(如果可以测量的话)。

Atomicity 可能是个问题。根据您的代码示例,我们有字段speed,该字段通过属性Speed公开显示。如果方法MultiplySpeed需要对值执行多次更新,那么在计算正在进行时,这些中间值将在不同时间通过Speed属性提供。无论您是直接更新字段还是通过属性更新字段,都是如此。在这种情况下,最好先将值放入局部变量,将其用于计算,并在完成后将该变量的值赋回属性。

最后,其他副作用。可能更改Speed的值应该引发事件(例如SpeedChanged)。在这种情况下,在计算完成之前不进行更新也是一个好主意。

我喜欢将该属性视为合同,将该字段视为实现。需要该值的任何人(除了我的类型的核心)都应该使用合同。只有在有充分理由绕过合同时才能依靠实施。

是的,如果你封装了对属性中字段的访问权限,那么自然地更改字段的名称将需要更少的更新(也许字段的名称变得不那么重要了。)

我希望这是有道理的,而且不是太偏离主题;)

答案 1 :(得分:8)

我同意Frederik's的答案。有一件事使得遵循他的建议稍微减少工作就是使用自动属性。这些只是自动生成标准getter / setter逻辑的属性。您没有得到任何验证,但您可以随后用标准的自动属性替换自动属性。这种替换不是一个重大变化。

这里我用自动属性替换了示例中的Speed属性。请注意,成员变量消失,您的类必须通过属性访问它。

public class Car
{
    public Car(int initialSpeed)
    {
        Speed = initialSpeed;
    }

    public int Speed { get; set; }

    public void MultiplySpeed(int multiply)
    {
        Speed *= multiply;
    }
}

您还可以使用另一种名为“get with private set”的风格。这意味着getter是公共的,但setter是私有的。你可以这样定义:

    public int Speed { get; private set; }

关于this.前缀的问题,通常无关紧要。唯一重要的是你定义了一个方法参数或局部变量,其名称与成员变量相同。然后,您可以使用this来访问成员变量。

答案 2 :(得分:1)

验证之类的事情可以在一个地方覆盖。该成员是封装的,您需要担心验证和其他类的其他事情。

在您当前的场景中,它确实没有什么区别,但是当您需要更改变量或需要添加行为时,使用属性会更容易,因为您只需要一个地方需要更改它。

答案 3 :(得分:1)

它不会添加缓存,但它确实允许一致的界面。

想象一下,你必须通过在将来添加一个常量来提高速度。使用成员变量将很困难,因为属性允许这种操作。

同样在类的内部,您应该再次访问该属性以保持一致性(想象一下您有一个直接访问成员变量的类的上述场景)。

答案 4 :(得分:1)

我所知道的唯一真正原因是是否从装配体外部访问该区域。在这种情况下,如果您想为该字段添加灯光功能(可能设置脏标志或验证更改),您必须将其更改为一个属性,该属性会更改调用程序集查看它的方式,这也需要重建。在极少数情况下,您可能会发现您无法控制该程序集,那么您就会遇到问题。

不要让OO狂热者告诉你使用公共字段是错误的,尽管我可能会同意自动属性使得这个论点有点没有实际意义。

答案 5 :(得分:1)

事实上,如果没有额外的逻辑,公开声明的字段和具有私有后备存储的公共属性之间没有太大区别。话虽如此,仍然认为使用属性是最佳做法。

在每个人都向我推断可扩展性之前,请记住,如果以后需要添加功能,可以使用属性保留名称,并为后备存储引入新名称,这样就不会发生重大变化。

答案 6 :(得分:0)

有一件事你忘了提及,属性会帮助你扩展你的课程。 如果您的类设计得当,基类中的变量应为private。没有实际属性public属性。您无法从扩展类中访问这些私有变量。我们正在谈论公共与私人,我不会因为某种原因而受到保护:)。

值得一提的是:

  • 扩展课程时的属性助手
  • 属性让我的代码更具可读性(另外this.privateVariable verson PublicPropertyVariableName)
  • 属性可以确保只读,私有集,公共获取等(对其他程序员来说更易读)。考虑一个IDentifier需要公共获取而非私人集合
  • 的情况
  • 就我个人来说,太多的获取/设置似乎使代码复杂化,使代码可读性降低,太多额外的不必要的语法
  • 继承/扩展到扩展类不允许继承私有变量,属性就是答案。 (再次没有提到受保护的,这是一个不同的故事)
  • 对我来说即使班级有私有变量,我的类方法仍然使用该属性来访问或使用该私有变量
  • 不要忘记验证,这样可以更容易地验证特别是可读性。

这些只是一些常见的事情(我的大部分都是2美分)。

答案 7 :(得分:0)

在我看来,语言设计被打破了。不应该有两种方法来处理那么多语义重叠的事情。属性/字段应该无缝地提供两种方法的好处,具体取决于它们的使用方式。如果程序对Property功能的使用最少,则它们的行为应与field相同。此外,不需要声明空的get;并设定;这种情况下的方法。这些差异让我觉得是人为的。

这是一门很棒的语言;而且大部分都很干净。这并不意味着它不应该在“下一次”改进。