C#基本属性理解

C#基本属性理解,c#,C#,我正在学习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 decima

我正在学习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;
        }
    }

第一种情况是处理属性,第二种情况是处理字段

与使用属性相比,使用字段有几个缺点。这些缺点包括:

  • 可以在属性的
    get
    set
    中设置断点,但不能在访问字段时设置断点
  • 公开字段违反了信息隐藏原则
  • 用于访问字段和属性的二进制MSIL代码是不同的,因此,如果将来将公共字段更改为公共属性,尽管源代码保持兼容,但任何依赖的二进制代码都会中断
  • 使用反射所需的代码是不同的,因此当您从字段移动到属性时,反射代码将中断

  • 长话短说:始终使用公共属性,而不要使用公共字段。

    有许多不同之处:

    • 属性由编译器转换为方法。因此,您可以将它们声明为虚拟的,并在派生类中重写它们
    • 使用属性,您可以将逻辑放入getter或setter(过滤、验证等)
    • 当您使用自动实现的属性(
      {get;set;}
      )时,似乎您也可以只使用公共字段。但是,使用属性意味着您可以在以后更改getter或setter实现,而无需更改类公开的接口。如果您使用了一个字段,并且希望在读取该字段时实现过滤,则必须引入一个新方法,将该字段设置为私有字段,并断开该类型的所有现有使用者
    就我个人而言,我认为自动实现的属性促进了糟糕的风格,因为它们不鼓励封装。像ReSharper这样的工具也喜欢使用
    {get;set}
    访问器生成属性。因此,新手开发人员通常会得到具有大量属性的类,这些属性将类型的状态公开给世界。默认情况下,您至少应该使用
    {get;private set;}

    通过提供get(访问器)和set(mutator)方法,您可以控制访问和变异。 例如:

    您有一个属性,不希望将其设置为任何大于15的值。因此,在set方法中设置必要的限制。除非使用set方法,否则无法控制


    但是在您的示例中,get和set方法是默认的,意味着不控制任何内容。

    属性背后的主要原因是以受控的方式保护和显示私有数据

    事实上,属性在使用中表现出如下能力:

    public virtual int AlbumId 
    { 
        get { // ... some magical operations ... }
        set { // ... some magical operations ... }
    }
    
    关于你的主要问题-本例中的区别是什么-主要关注点是
    virtual
    关键字

    此关键字导致属性可重写,因此任何其他代码都可以重写默认的
    get方法。这意味着您拥有自己的默认行为,其他代码(在实体框架中非常常用)实现它们自己的逻辑


    你例子中的第二个不是属性,所以它们不能表达这种神奇的能力

    请参见“仅能访问类”属性没有用处。属性应该有一些值。Get and Set将设置值并获取值。谢谢各位,我将删除我的question@bluebill1049谢谢你的提问,我了解了很多东西,但是设置属性和直接使用classname.variablename等值有什么区别吗?@M.N.S.@M.N.S:从技术上讲,语法是一样的,但是在引擎盖下有一些不同。例如,在您的情况下(虚拟属性),您可以在派生类中重写它(请参见我的编辑)。不,不,不,只要忘记虚拟和所有,如果albumid等是在公共类中公开定义的,那么通过继承,我们也可以像classname.variablename一样直接访问它们。那么为什么要使用属性呢?任何特定的好处???通常我们使用属性来限制访问(例如,get是公共的,set是受保护的或私有的);对于复杂输出(get),例如,如果标题为null或空,则将AlbumId返回为0;用于验证(设置),例如,您可以在尝试将负值设置为AlbumId时引发异常;对于接口实现-您可以将属性放入接口(属性是一个方法),但不能放入字段;对于多态行为,您可以设置属性,但不能设置字段为VitualTanks,这是有意义的
    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;
          }
        }
      ... 
    }
    
    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 virtual int AlbumId 
    { 
        get { // ... some magical operations ... }
        set { // ... some magical operations ... }
    }