Answers:
简短的回答:是的,有需要时。否则,请使用自动实现的属性获取器和设置器,例如private string Whatever { get; set;}
这是何时使用私有设置器的完整说明:C#属性用法。
这里已经有一些不错的答案,但是我认为其中大多数都错过了您的问题的要点:
我见过有人为每个成员(无论是否私有)都进行财产管理……这有意义吗?
我认为这对于每个成员来说都是很少必要的。从...开始
private string Whatever;
以后当您需要对该特定成员进行封装或有条件断点时,您仍然可以将其替换为具有相同名称的属性-在大多数情况下,无需更改使用的代码Whatever
。但是请注意,两者之间存在细微的差异,请参阅本SO帖子中的 Brian Rasmussen的答案 (链接也由Emmad Kareem提供,+ 1)。
私有属性对于封装类内部事件的行为非常有用。仅仅因为它们是私有的,并不意味着您不应该利用属性赋予您的语法糖。
但是,给出的示例很糟糕。这样的样板属性获取器和设置器几乎总是一个坏主意。如果您使用的是C#3.0或更高版本,则自动属性是一个更好的主意:
private string Whatever { get; set; };
它更短,更干净并且可读性更高。实际上,它仅比声明后备变量长。
不过,最重要的是,可以将自动属性随时转换为完整属性,而无需更改程序其余部分的语义!因此,如果您需要添加验证或错误处理,则可以轻松实现。
就是这样,我一直以为您不能拥有只读属性,以仅能写入构造函数中的值(我更喜欢不可变类型),这是很可惜的,但这是在C#6.0中添加为“自动属性初始化程序”,您可以执行以下操作:
private string Whatever { get; } = ...;
要么
private string Whatever { get; };
随着
Whatever = ...;
在构造函数中。
我个人将其用作缓存机制,我们可以称其为属性级缓存。
private List<User> users;
private List<User> Users
{
get
{
if(users == null) users = new UserManager().GetUsers();
return users;
}
}
现在,在班级内的其他地方,我使用Users
属性而不是users
字段。
另一种可行的情况可能是您想在某个字段上实现某种逻辑,但是要在类中以集中方式实现。因此,您都可以为字段创建GetFoo()
方法或Foo
属性foo
。
private string foo;
private string Foo
{
get
{
return "Mr. " + foo;
}
}
还有其他需要考虑的事项:
实际属性是实现细节。OOP的目标之一是在可行的情况下尽量减少对实施细节的暴露。
这样做的原因是,如果您隐藏属性并仅通过getter和setter公开它们,则您拥有更多的控制权。例如,您的getter可以验证其输入并防止将该属性设置为无效状态。如果更改值的能力是时间紧迫的,那么设置者也可以防止这种情况。无论出于何种原因,该获取器都应获取实际值,因此可以进行延迟初始化和/或缓存。
公开getter和setter并隐藏属性意味着有时您根本不需要属性。您的getter可以在调用时计算值,或将任务委派到其他地方,或使其符合要求的任何东西。关于您的班级,重要的是您可以从班级访问的信息,而不是内部信息的表示方式。
当然,如果类之外的任何事物都不能直接访问属性,则没有负面影响,那么您应该将其公开。但是,以我的经验来看,这种情况相对较少。
我知道这是一个古老的问题,@ Yusubov所说的一切都是正确的,但是关于第二个问题,即关于二传手中特定逻辑的要点,并且由于我没有看到任何人特别提及这一点,所以一个完美的例子就是当您上课时实现INotifyPropertyChanged
接口。
在WCF和Silverlight中大量使用此功能,通过它的设置器中的逻辑,您可以知道何时更改了特定属性,如以下类中所示:
public class Settings : INotifyPropertyChanged
{
public Settings()
{
this.CountryField = String.Empty;
}
private string CountryField;
public string Country
{
get { return this.CountryField; }
set
{
if (Object.ReferenceEquals(this.CountryField, value)) { return; }
this.CountryField = value;
this.RaisePropertyChanged("Country");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if (propertyChanged != null)
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}