在我看到的大部分代码中(在 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 中提供了一个漂亮的图标并放在类图中的特殊部分!
请参阅这篇文章 http://blog.codinghorror.com/properties-vs-public-variables/
具体来说
反射在变量和属性上的工作方式不同,所以如果你依赖反射,使用所有属性会更容易。
您不能对变量进行数据绑定。
将变量更改为属性是一项重大更改。
三个原因:
您不能像属性一样覆盖子类中的字段。您最终可能需要更复杂的 getter 或 setter,但如果它是一个字段,更改它会破坏 API。习俗。这就是它的完成方式。
我敢肯定还有更多我没有想到的原因。
在 .Net 3.x 中,您可以使用如下自动属性:
public int Age { get; set; }
而不是像这样自己声明私有字段的旧学校方式:
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
这使得它像创建一个字段一样简单,但没有重大更改问题(除其他外)。
当您创建私有字段名称和实际获取和设置名称字段值的简单公共属性名称时
public string Name
{
get { return name; }
}
并且你在你的类之外的任何地方都使用这个属性,有一天你决定这个类的 Name 属性实际上将引用 lastName 字段(或者你想返回一个字符串“我的名字:”+name),你只需更改属性内的代码:
public string Name
{
get { return lastName; //return "My name: "+name; }
}
如果您在外部代码中的任何地方都使用公共字段名称,那么您必须在使用它的任何地方将 name 更改为 lastName。
那么它确实有所作为。公共数据可以在对象实例不知道的情况下更改。使用 getter 和 setter 时,对象总是知道已经进行了更改。
请记住,封装数据只是朝着更好的结构化设计迈出的第一步,它本身并不是最终目标。
在以下情况下,您必须使用属性:
当您需要将属性中的数据序列化为某种格式时。当您需要覆盖派生类中的属性时。当您使用某些逻辑实现 get 和 set 方法时。例如,当您实现单例模式时。当您从接口派生时,在其中声明了属性。当您遇到与反射相关的具体问题时。
这取决于?
我总是使用 getter 和 setter,因为他们创建了这个快捷方式:
公共 int Foo { 获取;放; }
在编译时它被翻译。现在你不能对它感兴趣,但它就在那里,如果你需要花哨,你以后再拼出来。
无论是公开的、私有的还是受保护的……这完全取决于您希望谁能够调整数据。我们经常使用继承,这对我们来说是一种非常常见的方法,因此只有孩子可以编辑某些属性。
protected _foo;
public Foo
{
get { return _foo; }
} //lack of set intentional.
我不敢相信有 11 个答案,没有人这么说:
并非所有私有字段都应作为公共属性公开。您当然应该为任何需要非私有的东西使用属性,但您应该尽可能多地保持您的类私有。
有很多原因。
主要是:
设置变量后,您可以执行一些其他功能
您可以阻止设置并仅提供 get
某些“事物”仅适用于属性(例如 DataBinding)
您可以隐藏属性的实现 [也许它是一个 ViewState 变量,在 ASP.NET 中)。
关键是 - 如果您想确保每次引用 myInt
时都会发生一些特殊情况(写入日志文件,将其更改为 42 等),该怎么办?如果没有 getter 和 setter,你就无法做到这一点。有时,明智的做法是针对您可能需要的内容进行编程,而不是针对您现在需要的内容进行编程。
Point
的未来版本可能在属性 getter 或 setter 中有用的任何事情吗?如果 Point
是具有 virtual 属性的类,则未来派生类可能能够添加有用的行为,但由于特定的 Point
实例不知道它们的用途,并且期望接受 X
和 Y
的任何 Int32
值,我想不出未来的实现可能会添加什么。
实际上,如果您使用 Silverlight,您会意识到不能将字段设置为静态资源,因此您必须使用属性(甚至访问 const
)。
我已经意识到,当我尝试联合我在 Composite Guidance (PRISM) 中使用的区域名称时。
但是,这只是语言限制,除了 static
/const
字段外,我总是使用属性。
这个想法是您不应该意外/无意地更改外部类私有字段的值。当您使用 get 和 set 时,这意味着您正在有意且有意地更改类私有字段。
将值设置为私有字段只会更改该字段,但将它们放在属性中您可以处理其他参数,例如,您可以在设置值后调用方法
private string _email; public string Email { get { return this._email; } set { this._email = value; ReplaceList(); //** } }
简而言之,您的问题的答案是访问修饰符,即公共和私有。
如果您使用:
public int myInt;
public int MyInt
{
get { return myInt; }
set { myInt = value }
}
那么 MyInt 属性和 myInt 变量在要修改的项目中都可用。意思是,如果你的类假设 A 被类假设 B 继承,那么 myInt 和 MyInt 都可以修改并且不能应用检查。假设如果某些特定条件通过,您希望可以在派生类中设置 myInt 值。
这只能通过将字段设为私有并将属性设为公共来实现。这样只有属性可用,并且可以根据它设置条件。