C#的基本属性理解
本文关键字:属性 | 更新日期: 2023-09-27 18:26:43
我正在学习C#,遇到了以下代码
public class Album
{
public virtual int AlbumId { get; set; }
public virtual int GenreId { get; set; }
public virtual int ArtistId { get; set; }
public virtual string Title { get; set; }
public virtual decimal Price { get; set; }
public virtual string AlbumArtUrl { get; set; }
public virtual Genre Genre { get; set; }
public virtual Artist Artist { get; set; }
}
只是想知道下面的有什么不同?我的意思是,没有获取和设置,你也可以访问这些公共财产。是什么让这些东西变得重要?
public class Album
{
public virtual int AlbumId;
public virtual int GenreId;
public virtual int ArtistId;
public virtual string Title;
public virtual decimal Price;
public virtual string AlbumArtUrl;
public virtual Genre Genre;
public virtual Artist Artist;
}
控制对象私有字段值。例如,如果您不想允许整数为null或负值。
bool started;
public bool Started
{
get { return started; }
set
{
started = value;
if (started)
OnStarted(EventArgs.Empty);
}
}
another example
int positiveNumber;
public int PositiveNumber
{
get { return positiveNumber; }
set {
if (value < 0)
positiveNumber = 0;
else positiveNumber = value;
}
}
并且只读属性的另一种实现方式可以如下
int positiveNumber;
public int PositiveNumber
{
get { return positiveNumber; }
}
您不能声明虚拟字段
public class Album
{
public virtual int AlbumId; // <- Syntax error
...
}
属性实际上是方法:get或(and)set,因此
public class Album
{
public virtual int AlbumId { get; set; } // <- Both get and set methods declared as virtual ones
...
}
如果你想的话,你可以在派生类中覆盖这些get或(和)set:
public class GreatAlbum: Album {
private Boolean m_IsGreat;
public override int AlbumId {
get {
if (m_IsGreat)
return base.AlbumId
else
return 0;
}
set {
m_IsGreat = (value != 0);
base.AlbumId = value;
}
}
...
}
通过提供get(访问器)和set(赋值器)方法,您可以控制访问和赋值。例如:
您有一个不希望设置为任何值超过15的属性。所以你在你的集合方法中做了必要的限制。除非那个set方法,否则你无法控制。
但在您的示例中,get和set方法是默认的,意味着不控制任何内容。
事实上,属性在这样的使用中显示了它们的能力:
public virtual int AlbumId
{
get { // ... some magical operations ... }
set { // ... some magical operations ... }
}
关于你的主要问题——在这个例子中有什么不同——主要需要注意的是virtual
关键字。
此关键字会导致属性可重写,因此任何其他代码都可以重写默认的get;
方法。它要求您拥有自己的默认行为,其他代码(在实体框架中非常使用)实现自己的逻辑!
你的例子中的第二个不是属性,所以它们不能表达这种神奇的能力。。。!
在第一种情况下,您处理的是属性,在第二种情况下处理的是字段。
与使用属性相比,使用字段有几个缺点。这些缺点包括:
- 可以在属性的
get
或set
中设置断点,但不能在访问字段时设置断点 - 公开字段违反了信息隐藏原则
- 用于访问字段和属性的二进制MSIL代码是不同的,因此,如果将来将公共字段更改为公共属性,尽管源代码保持兼容,但任何依赖的二进制代码都会中断
- 使用反射所需的代码是不同的,因此当您从字段移动到属性时,反射代码将中断
长话短说:总是使用公共属性,NEVER使用公共字段。
存在许多差异:
- 属性由编译器转换为方法。因此,您可以将它们声明为虚拟的,并在派生类中重写它们
- 使用属性,您可以将逻辑放入getter或setter中(过滤、验证等)
- 当您使用自动实现的属性(
{ get;set;}
)时,似乎您还不如只使用公共字段。但是,使用属性意味着您可以在以后更改getter或setter实现,而无需更改类公开的接口。如果您使用了一个字段,并且希望在读取该字段时实现过滤,则必须引入一种新方法,使该字段私有,并断开该类型的所有现有使用者
就我个人而言,我认为自动实现的属性助长了糟糕的风格,因为它们不鼓励封装。像ReSharper这样的工具也喜欢用{get;set}
访问器生成属性。因此,新手开发人员通常最终会得到具有大量{get;set;}
属性的类,这些属性将类型的状态暴露给世界。默认情况下,您至少应该使用{get; private set;}
。