当前位置:  开发笔记 > 编程语言 > 正文

字段和属性之间有什么区别?

如何解决《字段和属性之间有什么区别?》经验,为你挑选了12个好方法。

在C#中,是什么使字段与属性不同,何时应该使用字段而不是属性?



1> Cory..:

属性公开字段.字段应该(几乎总是)保持对类的私有,并通过get和set属性进行访问.属性提供了一个抽象级别,允许您更改字段,同时不影响使用您的类的东西访问它们的外部方式.

public class MyClass
{
    // this is a field.  It is private to your class and stores the actual data.
    private string _myField;

    // this is a property. When accessed it uses the underlying field,
    // but only exposes the contract, which will not be affected by the underlying field
    public string MyProperty
    {
        get
        {
            return _myField;
        }
        set
        {
            _myField = value;
        }
    }

    // This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
    // used to generate a private field for you
    public int AnotherProperty{get;set;} 
}

@Kent指出,属性不需要封装字段,它们可以在其他字段上进行计算,或用于其他目的.

@GSS指出,当访问属性时,您还可以执行其他逻辑,例如验证,这是另一个有用的功能.


值得注意的是,封装字段不需要属性.该物业后面可能没有任何田地.它可能是一个计算或返回一个常数或其他什么.
你的答案在编辑之前是正确的,并且奇怪地提出了不正确的评论.属性应始终封装一个或多个字段,并且永远不应进行任何繁重的提升或验证.如果需要使用UserName或Password等属性进行验证,请将其类型从字符串更改为[Value Objects](http://bit.ly/1DX1pgh).类创建者和消费者之间有一个未说出口的合同.字段保持状态,属性使用一个或多个字段显示状态,空格改变状态(繁重提升),功能执行查询(繁重提升).这不是石头,只是松散的期望.
"虽然不会影响外部方式,但是使用你的课程的东西可以访问它们." 原谅我,如果我错误地理解了,那么,为什么在属性前需要访问修饰符,如果它背后的字段似乎处理这个?即为什么要将财产制成公共以外的其他财产?
@jpaugh如果我是班级消费者,我会遵循班级创建者设定的合同.如果属性是`string`,我的合同是:指定任何长度达到~2,2il的字符.如果属性是`DateTime`,我的合同是:分配DateTime限制内的任何数字,我可以查找.如果创建者向设置者添加约束,则不传达这些约束.但是,如果创建者将类型从`string`更改为`Surname`,那么他们的新Surname类会传递约束,而属性`public Surname LastName`则没有setter验证.此外,`Surname`是可重复使用的.
因为在我的例子中,`Surname`是可重用的,所以稍后你不必担心将属性设置器中的那些验证复制/粘贴到代码中的其他位置.如果您更改了Surnames的业务规则,也不会想知道Surname的验证是否在多个位置.查看我发布的有关Value Objects的链接

2> danswain..:

面向对象的编程原则说,类的内部工作应该隐藏在外部世界之外.如果您公开一个字段,那么您实际上是暴露了该类的内部实现.因此,我们使用Properties(或Java的方法)来包装字段,以使我们能够在不破坏代码的情况下更改实现,具体取决于我们.看到我们可以在属性中放置逻辑也允许我们在需要时执行验证逻辑等.C#3有可能令人困惑的autoproperties概念.这允许我们简单地定义属性,C#3编译器将为我们生成私有字段.

public class Person
{
   private string _name;

   public string Name
   {
      get
      {
         return _name;
      }
      set
      {
         _name = value;
      }
   }
   public int Age{get;set;} //AutoProperty generates private field for us
}


+1提及autoproperties - 我认为这是许多答案(和其他地方)忘记带来的东西.没有这个解释,它仍然很难理解`public int myVar {get; 组; 我真的代表(并且我认为这是这个问题得到的至少50%命中的原因).
+1也提到auto,并提及它是如何工作的("AutoProperty为我们生成私有字段")这是我一直在寻找的问题的答案.在研究时,我没有在MSDN的页面上看到有关私有字段被创建并导致混淆的任何迹象.我猜这就是这个意思?"在自动实现的属性上允许使用属性,但显然不在支持字段上,因为无法从源代码访问这些属性.如果必须在属性的支持字段上使用属性,只需创建常规属性." 但不确定.
请注意,给定的示例未封装蹲坐。此属性为私有字段提供100%的完全访问权限,因此这根本不是面向对象的。在这种情况下,您最好有一个公共场所。当然,它有助于将来(少量地)重构代码,但是任何值得的IDE都可以通过几次击键将字段转换为属性。对于属性的工作方式,从技术上来说,答案可能是正确的,但是对于它们的使用并不能给出很好的“ OOP解释”。
@kai我同意答案过度简化的事情并没有显示自动属性的所有功能,但我不同意这不是面向对象的.您可能希望[检查字段和属性之间的差异](http://stackoverflow.com/questions/1180860/public-fields-versus-automatic-properties).字段不能是虚拟的,而"虚拟"本身也是面向对象编程的一部分.

3> Hans Løken..:

一个重要的区别是接口可以具有属性但不具有字段.对我来说,这强调了属性应该用于定义类的公共接口,而字段用于在类的私有内部工作中使用.作为一项规则,我很少创建公共字段,同样我很少创建非公共属性.



4> Chris..:

我将举几个使用可能使齿轮转动的属性的例子:

延迟初始化:如果你有一个对象的属性,加载成本很高,但在正常的代码运行中没有被访问,你可以通过属性延迟加载.这样,它只是坐在那里,但是第一次另一个模块试图调用该属性时,它会检查底层字段是否为空 - 如果是,则继续并加载它,调用模块不知道.这可以大大加快对象初始化.

脏跟踪:我在StackOverflow上从我自己的问题中实际了解到了这一点.当我有很多对象在运行期间可能已经更改了值时,我可以使用该属性来跟踪是否需要将它们保存回数据库.如果没有对象的单个属性发生更改,则IsDirty标志不会被触发,因此在决定需要返回数据库时,保存功能将跳过它.


@juanpastas:关于脏跟踪的属性的优点是,如果属性设置器将设置"脏"标志,那么在未设置标志的场景中,代码将不必检查任何属性的值以查看如果他们可能已经改变了 相反,如果一个对象将其属性公开为字段,那么必须将所有字段的内容与之前的值进行比较(这不仅增加了进行比较的时间,而且还意味着代码必须*具有*之前的值).

5> Jehof..:

使用Properties,可以在更改属性的值(也就是PropertyChangedEvent)时或在更改值以支持取消之前抛出事件.

这对于(直接访问)字段是不可能的.

public class Person {
 private string _name;

 public event EventHandler NameChanging;     
 public event EventHandler NameChanged;

 public string Name{
  get
  {
     return _name;
  }
  set
  {
     OnNameChanging();
     _name = value;
     OnNameChanged();
  }
 }

 private void OnNameChanging(){
   EventHandler localEvent = NameChanging;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }

 private void OnNameChanged(){
   EventHandler localEvent = NameChanged;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }
}


我花了很长时间才找到这个.这是[MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel).谢谢 !:)

6> Sarath Avana..:

因为他们中许多人与技术的利弊解释PropertiesField,是时候进入实时的例子.

1.属性允许您设置只读访问级别

考虑的情况下dataTable.Rows.CountdataTable.Columns[i].Caption.他们来自全班DataTable,都是公开的.访问级别与它们的区别在于我们无法设置值,dataTable.Rows.Count但我们可以读取和写入dataTable.Columns[i].Caption.这可能通过Field吗?没有!!!这只能用Properties.

public class DataTable
{
    public class Rows
    {       
       private string _count;        

       // This Count will be accessable to us but have used only "get" ie, readonly
       public int Count
       {
           get
           {
              return _count;
           }       
       }
    } 

    public class Columns
    {
        private string _caption;        

        // Used both "get" and "set" ie, readable and writable
        public string Caption
        {
           get
           {
              return _caption;
           }
           set
           {
              _caption = value;
           }
       }       
    } 
}

2. PropertyGrid中的属性

您可能Button在Visual Studio中使用过.它的属性显示在PropertyGrid类似Text,Name等等.当我们拖放一个按钮,当我们点击属性,它会自动查找类Button和过滤器Properties和显示,PropertyGrid(这里PropertyGrid将不显示Field,即使它们是公共的).

public class Button
{
    private string _text;        
    private string _name;
    private string _someProperty;

    public string Text
    {
        get
        {
           return _text;
        }
        set
        {
           _text = value;
        }
   } 

   public string Name
   {
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   } 

   [Browsable(false)]
   public string SomeProperty
   {
        get
        {
           return _someProperty;
        }
        set
        {
           _someProperty= value;
        }
   } 

PropertyGrid,属性NameText将显示,但不会SomeProperty.为什么???因为属性可以接受属性.如果[Browsable(false)]错误则不显示.

3.可以在Properties中执行语句

public class Rows
{       
    private string _count;        


    public int Count
    {
        get
        {
           return CalculateNoOfRows();
        }  
    } 

    public int CalculateNoOfRows()
    {
         // Calculation here and finally set the value to _count
         return _count;
    }
}

4.只能在绑定源中使用属性

绑定源有助于我们减少代码行数.Fields不被接受BindingSource.我们应该用Properties它.

5.调试模式

考虑一下我们Field用来持有价值.在某些时候,我们需要调试并检查该字段的值为null的位置.在代码行数超过1000的情况下很难做到.在这种情况下我们可以使用Property并可以在里面设置调试模式Property.

   public string Name
   {
        // Can set debug mode inside get or set
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   }


在我的回答中阅读我的第一句话.我特意告诉我,我不打算在这里重复一切.这是没有意义的!!!人们将首先看一下描述,然后是例子.标记的答案很好地描述了描述,但我添加了一些有意义的实时场景和示例.在评论@Dawid Ferenczy之前,请确保从读者的角度思考

7> 小智..:

差异 - 用途(何时以及为何)

字段是直接宣布类或结构的一个变量.类或结构可以包含实例字段或静态字段或两者.通常,您应该将字段用于具有私有或受保护可访问性的变量.应通过方法,属性和索引器提供类暴露给客户端代码的数据.通过使用这些构造来间接访问内部字段,可以防止无效的输入值.

属性是,提供了一个灵活的机制来读,写,或计算私有字段的值的构件.属性可以像它们是公共数据成员一样使用,但它们实际上是称为访问器的特殊方法.这样可以轻松访问数据,并且仍然有助于提高方法的安全性和灵活性.属性使类能够公开获取和设置值的公共方式,同时隐藏实现或验证代码.get属性访问器用于返回属性值,set访问器用于分配新值.



8> Scott Wisnie..:

属性的主要优点是允许您更改对象上的数据访问方式,而不会破坏它的公共接口.例如,如果您需要添加额外的验证,或者将存储的字段更改为计算结果,则可以在最初将该字段作为属性公开时轻松完成.如果您只是直接暴露了一个字段,那么您必须更改类的公共接口以添加新功能.该更改将破坏现有客户端,要求在他们使用新版本的代码之前重新编译它们.

如果你编写一个专为广泛使用而设计的类库(比如数百万人使用的.NET Framework),这可能是一个问题.但是,如果你在一个小代码库内写一个内部使用的类(比如<= 50 K行),这真的不是什么大问题,因为没有人会受到你的更改的不利影响.在这种情况下,它实际上只取决于个人偏好.



9> Rune Grimsta..:

在后台,属性被编译为方法.所以一个Name属性被编译成get_Name()set_Name(string value).如果您研究编译的代码,您可以看到这一点.因此,使用它们时会产生(非常)小的性能开销.通常,如果将字段暴露给外部,您将始终使用属性,如果需要对值进行验证,则通常会在内部使用该属性.



10> Brian Rasmus..:

属性支持非对称访问,即您可以使用getter和setter,也可以只使用其中一个.类似地,属性支持getter/setter的个人可访问性.字段始终是对称的,即您始终可以获取和设置值.对此的例外是readonly字段,显然在初始化后无法设置.

属性可能会运行很长时间,有副作用,甚至可能抛出异常.字段很快,没有副作用,永远不会抛出异常.由于副作用,属性可能会为每个调用返回不同的值(可能是DateTime.Now的情况,即DateTime.Now并不总是等于DateTime.Now).字段始终返回相同的值.

字段可以用于out/ref参数,属性可以不用.属性支持额外的逻辑 - 这可以用于实现延迟加载等.

属性通过封装获取/设置值的任何方式来支持抽象级别.

在大多数/所有情况下使用属性,但尽量避免副作用.



11> 小智..:

如果希望私有变量(字段)可以从其他类访问类的对象,则需要为这些变量创建属性.

例如,如果我有名为"id"和"name"的变量是私有的,但可能存在这种变量在类之外进行读/写操作所需的情况.在这种情况下,属性可以帮助我根据为属性定义的get/set来读取/写入该变量.属性可以是readonly/writeonly/readwrite.

这是演示

class Employee
{
    // Private Fields for Employee
    private int id;
    private string name;

    //Property for id variable/field
    public int EmployeeId
    {
       get
       {
          return id;
       }
       set
       {
          id = value;
       }
    }

    //Property for name variable/field
    public string EmployeeName
    {
       get
       {
          return name;
       }
       set
       {
          name = value;
       }
   }
}

class MyMain
{
    public static void Main(string [] args)
    {
       Employee aEmployee = new Employee();
       aEmployee.EmployeeId = 101;
       aEmployee.EmployeeName = "Sundaran S";
    }
}



12> Joe Amenta..:

这里的第二个问题,“当应在现场使用,而不是财产?”,仅在简要介绍了这对方的回答还挺这一个了,但没有真正的细节。

一般而言,所有其他答案都是关于良好设计的问题:相对于公开字段,更喜欢公开属性。虽然你可能不会经常发现自己说“哇,想象有多少糟糕的事情是,如果我做了,而不是财产这个领域”,这是这么多更为罕见想到的情况下,你会说:“哇,感谢上帝,我在这里使用的是田地,而不是财产。”

但是,字段具有优于属性的一个优点,那就是它们可以用作“ ref” /“ out”参数。假设您有一个具有以下签名的方法:

public void TransformPoint(ref double x, ref double y);

并假设您想使用该方法来转换这样创建的数组:

System.Windows.Point[] points = new Point[1000000];
Initialize(points);

我认为这是最快的方法,因为X和Y是属性:

for (int i = 0; i < points.Length; i++)
{
    double x = points[i].X;
    double y = points[i].Y;
    TransformPoint(ref x, ref y);
    points[i].X = x;
    points[i].Y = y;
}

那将是相当不错的!除非您有其他证明的测量方法,否则没有理由发臭。但我相信,从技术上讲,它并不能保证达到以下速度:

internal struct MyPoint
{
    internal double X;
    internal double Y;
}

// ...

MyPoint[] points = new MyPoint[1000000];
Initialize(points);

// ...

for (int i = 0; i < points.Length; i++)
{
    TransformPoint(ref points[i].X, ref points[i].Y);
}

自己进行一些测量,带有字段的版本大约要花费带有属性的版本(.NET 4.6,Windows 7,x64,发布模式,未连接调试器)的61%的时间。该TransformPoint方法越昂贵,差异就越不明显。要自己重复一遍,请先注释掉第一行,然后注释掉第一行。

即使上面没有任何性能上的好处,在其他地方也可以使用ref和out参数可能是有益的,例如在调用Interlocked或Volatile系列方法时。 注意:如果这是您的新手,那么Volatile本质上是一种实现volatile关键字提供的相同行为的方法。因此,就像一样volatile,它不能神奇地解决所有线程安全问题,就像它的名字暗示的那样。

我绝对不希望我提倡您去“哦,我应该开始显示字段而不是属性”。关键是,如果您需要在带有“ ref”或“ out”参数的调用中定期使用这些成员,尤其是在那些可能是简单值类型,不太可能不需要属性的任何增值元素的调用上,可以争论。

推荐阅读
U友50081205_653
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有