ChatGPT解决这个技术问题 Extra ChatGPT

我应该使用公共属性和私有字段还是公共字段来存储数据?

在我看到的大部分代码中(在 SO,thecodeproject.com 上,我倾向于在我自己的代码中这样做),我已经看到为类包含的每个私有字段创建公共属性,即使它们是最get; set; 的基本类型,例如:

private int myInt;
public int MyInt 
{
     get { return myInt; }
     set { myInt = value }
}

我的问题是:这与以下有何不同:

public int MyInt;

如果我们应该使用属性而不是公共字段,为什么我们应该在这种特定情况下使用它们? (我不是在谈论更复杂的示例,其中 getter 和 setter 实际上做了一些特殊的事情,或者只有一个 get 或 set(仅读/写),而不仅仅是返回/设置私有字段的值)。它似乎没有添加任何额外的封装,只是在 IntelliSense 中提供了一个漂亮的图标并放在类图中的特殊部分!

这真的不是重复的吗?
很难相信这个问题直到现在才在这里被问到!
是的,我认为我做到了。等我追捕它...

J
Johnno Nolan

请参阅这篇文章 http://blog.codinghorror.com/properties-vs-public-variables/

具体来说

反射在变量和属性上的工作方式不同,所以如果你依赖反射,使用所有属性会更容易。

您不能对变量进行数据绑定。

将变量更改为属性是一项重大更改。


使用属性比使用字段更可取,因为您可以更改 get 和 set 块中的语句,而无需更改依赖于属性的类。
M
Max Schmeling

三个原因:

您不能像属性一样覆盖子类中的字段。您最终可能需要更复杂的 getter 或 setter,但如果它是一个字段,更改它会破坏 API。习俗。这就是它的完成方式。

我敢肯定还有更多我没有想到的原因。

在 .Net 3.x 中,您可以使用如下自动属性:

public int Age { get; set; }

而不是像这样自己声明私有字段的旧学校方式:

private int age;

public int Age
{
    get { return age; }
    set { age = value; }
}

这使得它像创建一个字段一样简单,但没有重大更改问题(除其他外)。


=1:你从哪里得到不能序列化的字段?
“你最终可能需要一个更复杂的 getter 或 setter,但如果它是一个字段,更改它会破坏 API。”并不真地。您可以安全地从:public int Joe;到私人 int _joe; public int Joe { get { //do something } set { //do something } } 您可能需要更改很多内部引用,但这不会破坏您的 API。
@John Saunders 这就是我读过的……这不是真的吗?这是真的吗?
@Russel Steen 好吧,也许不会破坏 API,但你必须重新编译
@Russell Steen - 当然这是一个突破性的变化。仅仅因为它在 C# 中看起来相同并不意味着它是相同的。您将字段访问更改为方法调用,这是完全不同的,任何调用代码都需要重新编译。
a
agnieszka

当您创建私有字段名称和实际获取和设置名称字段值的简单公共属性名称时

public string Name
{
   get { return name; }
}

并且你在你的类之外的任何地方都使用这个属性,有一天你决定这个类的 Name 属性实际上将引用 lastName 字段(或者你想返回一个字符串“我的名字:”+name),你只需更改属性内的代码:

public string Name
{
   get { return lastName; //return "My name: "+name; }
}

如果您在外部代码中的任何地方都使用公共字段名称,那么您必须在使用它的任何地方将 name 更改为 lastName。


P
PatrikAkerstrand

那么它确实有所作为。公共数据可以在对象实例不知道的情况下更改。使用 getter 和 setter 时,对象总是知道已经进行了更改。

请记住,封装数据只是朝着更好的结构化设计迈出的第一步,它本身并不是最终目标。


J
John Saunders

在以下情况下,您必须使用属性:

当您需要将属性中的数据序列化为某种格式时。当您需要覆盖派生类中的属性时。当您使用某些逻辑实现 get 和 set 方法时。例如,当您实现单例模式时。当您从接口派生时,在其中声明了属性。当您遇到与反射相关的具体问题时。


为什么你认为字段不能被序列化?
R
Russell Steen

这取决于?

我总是使用 getter 和 setter,因为他们创建了这个快捷方式:

公共 int Foo { 获取;放; }

在编译时它被翻译。现在你不能对它感兴趣,但它就在那里,如果你需要花哨,你以后再拼出来。

无论是公开的、私有的还是受保护的……这完全取决于您希望谁能够调整数据。我们经常使用继承,这对我们来说是一种非常常见的方法,因此只有孩子可以编辑某些属性。

protected _foo;  
public Foo  
{  
    get { return _foo; }
} //lack of set intentional.

J
John Saunders

我不敢相信有 11 个答案,没有人这么说:

并非所有私有字段都应作为公共属性公开。您当然应该为任何需要非私有的东西使用属性,但您应该尽可能多地保持您的类私有。


重新阅读问题 - 在这种情况下,我需要从课堂外访问这些私有字段。当然,您不会公开每个字段或给每个字段一个属性!
实际上,这个问题并没有说明您需要什么,只说明了您所看到的为每个私有字段创建的公共属性。如果您有需要公共访问的字段,那么它们不是私有字段,并且与您提出的问题不匹配。请编辑问题以明确您的代码中包含的内容,而不是您在“SO,thecodeproject.com”上看到的示例
N
Noon Silk

有很多原因。

主要是:

设置变量后,您可以执行一些其他功能

您可以阻止设置并仅提供 get

某些“事物”仅适用于属性(例如 DataBinding)

您可以隐藏属性的实现 [也许它是一个 ViewState 变量,在 ASP.NET 中)。


D
Dominic Rodger

关键是 - 如果您想确保每次引用 myInt 时都会发生一些特殊情况(写入日志文件,将其更改为 42 等),该怎么办?如果没有 getter 和 setter,你就无法做到这一点。有时,明智的做法是针对您可能需要的内容进行编程,而不是针对您现在需要的内容进行编程。


对于某些类型,这样的场景是现实的。对于其他人,他们不是。您能想到 Point 的未来版本可能在属性 getter 或 setter 中有用的任何事情吗?如果 Point 是具有 virtual 属性的类,则未来派生类可能能够添加有用的行为,但由于特定的 Point 实例不知道它们的用途,并且期望接受 XY 的任何 Int32 值,我想不出未来的实现可能会添加什么。
R
R4cOOn

实际上,如果您使用 Silverlight,您会意识到不能将字段设置为静态资源,因此您必须使用属性(甚至访问 const)。

我已经意识到,当我尝试联合我在 Composite Guidance (PRISM) 中使用的区域名称时。

但是,这只是语言限制,除了 static/const 字段外,我总是使用属性。


r
rayimag

这个想法是您不应该意外/无意地更改外部类私有字段的值。当您使用 get 和 set 时,这意味着您正在有意且有意地更改类私有字段。


M
Myra

将值设置为私有字段只会更改该字段,但将它们放在属性中您可以处理其他参数,例如,您可以在设置值后调用方法

private string _email;
public string Email
{
    get
    {
        return this._email;
    }
    set
    {
        this._email = value;
        ReplaceList(); //**
    }
}

好的,但他不需要做任何其他事情,只需返回_email。那么,usng 属性的原因是什么?原因就在我的答案中-供将来使用。
K
KamalDeep

简而言之,您的问题的答案是访问修饰符,即公共和私有。

如果您使用:

public int myInt;
public int MyInt 
{
     get { return myInt; }
     set { myInt = value }
}

那么 MyInt 属性和 myInt 变量在要修改的项目中都可用。意思是,如果你的类假设 A 被类假设 B 继承,那么 myInt 和 MyInt 都可以修改并且不能应用检查。假设如果某些特定条件通过,您希望可以在派生类中设置 myInt 值。

这只能通过将字段设为私有并将属性设为公共来实现。这样只有属性可用,并且可以根据它设置条件。