【问题标题】:Why are class members private and properties public? [duplicate]为什么类成员是私有的而属性是公共的? [复制]
【发布时间】:2017-04-02 06:35:15
【问题描述】:

在一个类中,我们将类成员声明为私有,但我们将属性定义为公共。

例如:

public class student
{
    private int StudentId;
    private string StudentName;
    private string Address;
} 

然后我们使用方法分配。

但是如果我们使用属性来获取设置定义公共喜欢。

public class student
{
    public int StudentId {get;set;};
    public string StudentName{get;set;};
    public string Address{get;set;};
} 

这背后的原因是什么?

【问题讨论】:

  • 你不要这样做因为它们是“类成员”或“属性”(顺便说一下,属性也是成员,更典型的是将它们分组静态成员和实例成员)。您通常希望封装实际的实现,因此当您访问它们时没有发生绑定逻辑的字段通常是私有的,而您可以控制写访问(谁可以写)和绑定逻辑(当您访问它们时会发生什么)的属性write) 更多时候是公开的。你想控制你的类型的公共表面,并隐藏实际的实现。
  • 没有强制您将字段用作私有字段或将属性用作公共,但通常变量是私有的,用于类的内部使用,而属性用于外部使用,因为它们可以在以下情况下执行代码他们正在获取/设置。

标签: c#


【解决方案1】:

一个类需要控制其公共成员的行为:即控制他们做什么

想象一下,例如,如果 private string StudentName; 被设为 public 并被外部代码(外部类 student)使用。然后你决定要添加一个验证来限制StudentName 的长度——你怎么能这样做呢?您必须在您的代码(可能还有使用此类的其他人的代码)中找到所有设置StudentName 值的实例,并在那里添加验证。

如果您使用的是 public string Student {get; set;},则不会 - 您可以轻松地将其更改为具有验证的显式属性:

private string _student;
public string Student
{
    get { return _student; }
    set { if(value.Length <= 20) _student = value;
}

即使用属性可以更容易地从类内部控制类成员的行为,维护封装和抽象

【讨论】:

    【解决方案2】:

    你是对的 - 属性通常用作公共属性。 虽然:您也可以定义这样的属性:

    public int StudentId {get; private set;}
    

    这将使其他类获得您的属性的值,但他们将无法更改它。

    想象一下,如果您要开发一个项目,例如其中包含许多复杂控件的程序集。如果您希望用户能够读取控件中的值,因为它是经过计算的,所以您给它一个公共 getter 而一个私有 setter,因为您不希望有人操纵内部发生的事情。

    【讨论】:

      【解决方案3】:

      不完全是这样。真正的规则是:

      尽可能严格地定义所有成员。

      所以,如果它可以是private,那么它就是private。否则,如果它必须是internalprotected 才能工作,那么它分别是internalprotected。否则,如果它必须是protected internal 才能工作,那么它就是protected internal。否则,它是 public,因为它必须是 public 才能工作(程序集之外不继承它的东西将不得不访问它。

      现在,说了这么多,通常情况下,我们将拥有大部分 private 字段和大部分 public 属性。

      让我们考虑一下是否有public 字段。这是有效的,会起作用,甚至在非常有限的情况下也很有用。然而它也更脆。拥有它public 可以让任何其他代码将其设置为任何值,无论多么愚蠢。没关系,因为当我们创建一个字段 public 时,我们是在说“没有愚蠢的值”。*

      但是如果我们突然意识到有一些愚蠢的值,或者我们需要在每次更改字段时做一些事情,或者我们需要处理一些仅属性的数据绑定。在这里,我们将不得不将字段变成一个属性,这是一个突破性的变化;任何使用这个类的代码都必须重新编译,如果我们是唯一使用这个类的人,这没什么大不了的,但如果它在一个被其他人使用的库中。

      如果它是一个属性,那么我们只需要将一个自动属性{ get; set; } 转换为一个具有自定义实现{ get { /* do stuff and return value */ } set { /* do stuff */ } } 的属性。从课堂外看,似乎什么都没有改变,我们也没有破坏任何东西。

      因此,如果您要创建一个字段 public,那么在 99.99% 的情况下,您最好使用那里的属性,以防万一。

      另一方面,如果我们有一个没有逻辑的private 属性,那么getter 和setter 方法不会给我们带来任何好处。不会有任何成本,但它们毫无意义。所以我们只使用一个字段。如果我们最终不得不在未来使用私有属性,那也没关系,因为唯一需要重新编译的代码就是有问题的类,而且我们无论如何都要重新编译它。

      因此,我们最终会遇到几乎所有字段都是 private 并且几乎所有没有任何自定义逻辑的属性都是 protectedpublic 的情况。

      *或者它是 privateinternal 类,我们从外部承诺不会将其设置为愚蠢的东西,但如果可以的话,最好执行承诺而不是做出承诺。

      【讨论】:

        【解决方案4】:

        不直接设置字段,而是通过属性,遵循封装的面向对象原则。这包括一个类是其对象包含的数据的老板。一个类应该始终控制对其数据的访问(无论是读取还是写入)。有时这意味着他们需要执行额外的步骤来确保数据的一致性。但即使他们不这样做,也应该对调用者隐藏不应该这样做的事实,因为这不关他们的事(关注点分离)。因此,简单的规则:对象数据没有快捷方式。如果你想得到一些,你必须让班级给你。在 C# 中,这就是属性的用途。

        【讨论】:

          【解决方案5】:

          使用属性并将其公开的背后有多种原因

          1. 将类字段标记为公开和公开是有风险的,因为您将 无法控制分配和返回的内容。

          2. 想要在值更改时闯入调试器?只需在 setter 中添加断点即可。

          3. 想要记录所有访问?只需将日志记录添加到 getter 即可。 属性用于数据绑定;字段不是。

          4. 为私有成员添加验证(比如值不能设置为负)。

          5. 在 null、空或零的情况下返回一些默认值。

          6. 属性可以声明为读/写、只读或只写。

          7. 其他好处,反射和数据绑定。

          【讨论】:

            【解决方案6】:

            在这个最简单的情况下没有特殊原因。但是如果你在开发中走得更远 - 它会变得非常清楚:你需要从实现中抽象出来并分离出一个接口,例如只是为了在单元测试中模拟学生。所以,从长远来看,你宁愿需要接口和属性,从一开始就以可模拟和可测试的方式编写它只是一种习惯

            public interface IStudent
            {
                int StudentId { get; set; }
                string StudentName { get; set; }
                string Address { get; set; }
            }
            
            public class Student : IStudent
            {
                public int StudentId { get; set; }
                public string StudentName { get; set; }
                public string Address { get; set; }
            }
            

            【讨论】:

              猜你喜欢
              • 2023-04-04
              • 1970-01-01
              • 1970-01-01
              • 2010-12-24
              • 2015-07-15
              • 2017-12-09
              • 2011-01-10
              • 2015-05-04
              • 2010-10-18
              相关资源
              最近更新 更多