为啥类成员是私有的而属性是公共的? [复制]

Posted

技术标签:

【中文标题】为啥类成员是私有的而属性是公共的? [复制]【英文标题】: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 StudentNameget;set;;
    public string Addressget;set;;
 

这背后的原因是什么?

【问题讨论】:

你不要这样做因为它们是“类成员”或“属性”(顺便说一下,属性也是成员,更典型的是将它们分组静态成员和实例成员)。您通常希望封装实际的实现,因此当您访问它们时没有发生绑定逻辑的字段通常是私有的,而您可以控制写访问(谁可以写)和绑定逻辑(当您访问它们时会发生什么)的属性write) 更多时候是公开的。你想控制你的类型的公共表面,并隐藏实际的实现。 没有强制您将字段用作私有字段或将属性用作公共,但通常变量是私有的,用于类的内部使用,而属性用于外部使用,因为它们可以在以下情况下执行代码他们正在获取/设置。 此解决方案可能会清除您的情况:***.com/questions/295104/…softwareengineering.stackexchange.com/questions/133015/… 见blogs.msdn.microsoft.com/vbteam/2009/09/04/… 【参考方案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】:

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

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

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

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

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

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

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

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

【讨论】:

【参考方案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; 

【讨论】:

以上是关于为啥类成员是私有的而属性是公共的? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

在Java中,如果这样写,为啥私有数据成员可以在类外部访问? [复制]

C#中继承类为啥可以通过属性访问基类的私有字段。

让公共成员变量访问 C++ 中同一类的私有成员

我们可以将基类的私有成员继承到派生类的公共成员中吗?

继承 Java 私有成员

TSLint - 您只能绑定到公共类成员(模板使用公共)