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

时间:2008-11-17 08:41:38

标签: c# properties field

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

32 个答案:

答案 0 :(得分:853)

属性公开字段。字段应该(几乎总是)保持对类的私有,并通过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指出,当访问属性时,您还可以执行其他逻辑,例如验证,这是另一个有用的功能。

答案 1 :(得分:232)

面向对象的编程原则说,类的内部工作应该隐藏在外部世界之外。如果您公开一个字段,那么您实际上是暴露了该类的内部实现。因此,我们使用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
}

答案 2 :(得分:147)

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

答案 3 :(得分:91)

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

  • Lazy Initialization :如果您的对象属性加载费用昂贵,但在正常运行的代码中无法访问,则可以通过财产。这样,它只是坐在那里,但是第一次另一个模块试图调用该属性时,它会检查底层字段是否为空 - 如果是,则继续并加载它,调用模块不知道。这可以大大加快对象初始化。
  • Dirty Tracking:我从StackOverflow上的own question实际了解到了这一点。当我有很多对象在运行期间可能已经更改了值时,我可以使用该属性来跟踪是否需要将它们保存回数据库。如果没有对象的单个属性发生更改,则IsDirty标志不会被触发,因此在决定需要返回数据库时,保存功能将跳过它。

答案 4 :(得分:46)

使用“属性”,可以在更改属性的值(也就是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);
   }
 }
}

答案 5 :(得分:41)

由于其中许多人已经解释了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中的属性

您可能在Visual Studio中使用过Button。它的属性显示在PropertyGrid中,如TextName等。当我们拖放按钮时,当我们点击属性时,它会自动找到类{{1} }和过滤器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。为什么???因为属性可以接受Attributes。如果[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。只有属性可用于绑定源

Binding Source帮助我们减少代码行数。 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;
        }
   }

答案 6 :(得分:28)

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

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

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

答案 7 :(得分:10)

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

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

答案 8 :(得分:8)

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

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

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

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

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

答案 9 :(得分:8)

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

答案 10 :(得分:5)

当您希望私有变量(字段)可以从其他类访问您的类的对象时,您需要为这些变量创建属性。

例如,如果我有名为“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";
    }
}

答案 11 :(得分:2)

MSDN上的这个页面有一个比较,并提示在以下情况下使用哪个:

https://msdn.microsoft.com/en-us/library/9d65as2e(v=vs.90).aspx

答案 12 :(得分:2)

基本区别和一般区别是:

字段

  • 始终同时授予获取权限和设置权限
  • 不能引起副作用(引发异常,调用方法,更改字段(除已设置的字段外)等)

属性

  • 并非总是授予访问权限和设置访问权限
  • 可以引起副作用

答案 13 :(得分:2)

我对一个字段的设计是一个字段只需要由它的父元素修改,因此需要修改它。结果变量变为私有,然后能够给出读取外部类/方法的权限。我只通过Get获取属性系统。然后该属性由该属性检索并且只读!如果你想修改它,你必须通过方法(例如构造函数),我发现,由于这种方式使你安全,我们可以更好地控制我们的代码,因为我们“法兰”。人们很可能总是将所有内容都公开,因此每个可能的情况,变量/方法/类等的概念......在我看来只是对代码开发和维护的帮助。例如,如果一个人恢复具有公共字段的代码,他可以做任何事情,因此与目标相关的事情“不合逻辑”,代码编写原因的逻辑。这是我的观点。

当我使用经典模型私有字段/公共只读属性时,对于10个私有字段,我应该写10个公共属性!代码可以更快。我发现私人二传手,现在我只使用私人二传手的公共财产。 setter在后台创建一个私有字段。

这就是为什么我的旧经典编程风格是:

public class MyClass
{
 private int _id;
 public int ID { get { return _id; } }
 public MyClass(int id)
 {
  _id = id;
 }
}

我的新编程风格:

public class MyClass
{
 public int ID { get; private set; }
 public MyClass(int id)
 {
  ID = id;
 }
}

答案 14 :(得分:2)

字段是普通成员变量或类的成员实例。属性是一个抽象来获取和设置它们的值。属性也称为访问器,因为如果将类中的字段公开为私有,它们提供了更改和检索字段的方法。通常,您应该将成员变量声明为private,然后为它们声明或定义属性。

  class SomeClass
  {
     int numbera; //Field

     //Property 
    public static int numbera { get; set;}

  }

答案 15 :(得分:2)

如果要使用线程基元,则必须使用字段。属性可以破坏您的线程代码。除此之外,科里所说的是正确的。

答案 16 :(得分:2)

从技术上讲,我认为没有区别,因为属性只是围绕用户创建的字段或由编译器自动创建的包装。属性的目的是强制封装并提供类似于轻量级的方法特征。 将字段声明为公共字段只是一种不好的做法,但它没有任何问题。

答案 17 :(得分:2)

(这应该是一个评论,但我不能发表评论,所以请原谅,如果它不适合作为帖子)。

我曾经在一个建议的做法是使用公共字段而不是属性的地方工作,当等效属性def只是访问字段时,如:

get { return _afield; }
set { _afield = value; }

他们的理由是,如果需要,将来可以将公共领域转换为财产。那时我觉得有点奇怪。从这些帖子来看,看起来这里也没有多少人同意。你可能会说什么试图改变一切?

编辑:我应该补充一点,这个地方的所有代码库都是同时编译的,所以他们可能认为更改类的公共接口(通过将公共字段更改为属性)不是问题。

答案 18 :(得分:2)

此外,属性允许您在设置值时使用逻辑。

所以你可以说你只想设置一个整数字段的值,如果值大于x,否则抛出异常。

非常有用的功能。

答案 19 :(得分:1)

IMO,属性只是我们之前使用的“SetXXX()”“GetXXX()”函数/方法/接口对,但它们更简洁和优雅。

答案 20 :(得分:1)

传统的私有字段是通过getter和setter方法设置的。为了减少代码,您可以使用属性来设置字段。

答案 21 :(得分:1)

当你有一个班级是&#34; Car&#34;。属性是颜色,形状..

其中,字段是在类范围内定义的变量。

答案 22 :(得分:1)

属性封装字段,因此您可以对要设置或检索的值执行其他处理。如果您不对字段值进行任何预处理或后处理,则使用属性通常会过度。

答案 23 :(得分:1)

来自维基百科 - Object-oriented programming

  

面向对象编程(OOP)是一种基于“对象”概念的编程范例,“对象”是包含数据的数据结构,以字段的形式,通常称为属性;和代码,以程序的形式,通常称为方法(强调添加)

属性实际上是对象行为的一部分,但旨在为对象的使用者提供使用对象数据的幻觉/抽象。

答案 24 :(得分:1)

属性是一种特殊的类成员,在属性中我们使用预定义的Set或Get方法。它们使用访问器,我们可以通过访问器来读取,写入或更改私有字段的值。

例如,让我们使用名为Employee的类,其中包含name,age和Employee_Id的私有字段。我们无法从课外访问这些字段,但我们可以通过属性访问这些私有字段。

为什么我们使用属性?

让课程字段公开&amp;暴露它是有风险的,因为你无法控制被分配的东西和返回。

通过一个例子清楚地理解这一点,让我们带一个有ID,密码,姓名的学生班。现在在这个例子中公共字段的一些问题

  • ID不应为-ve。
  • 名称不能设为null
  • 通行证应该是只读的。
  • 如果缺少学生姓名,则不应返回姓名。

要删除此问题,我们使用Get和set方法。

// A simple example
public class student
{
    public int ID;
    public int passmark;
    public string name;
}

public class Program
{
    public static void Main(string[] args)
    {
       student s1 = new student();
       s1.ID = -101; // here ID can't be -ve
       s1.Name = null ; // here Name can't be null
    }
}

现在我们举一个get和set方法的例子

public class student
{
    private int _ID;
    private int _passmark;
    private string_name ;
    // for id property
    public void SetID(int ID)
    {
        if(ID<=0)
        {
            throw new exception("student ID should be greater then 0");
        }
        this._ID = ID;
    }
    public int getID()
    {
        return_ID;
    }
}
public class programme
{
    public static void main()
    {
        student s1 = new student ();
        s1.SetID(101);
    }
    // Like this we also can use for Name property
    public void SetName(string Name)
    {
        if(string.IsNullOrEmpty(Name))
        {
            throw new exeception("name can not be null");
        }
        this._Name = Name;
    }
    public string GetName()
    {
        if( string.IsNullOrEmpty(This.Name))
        {
            return "No Name";
        }
        else
        {
            return this._name;
        }
    }
        // Like this we also can use for Passmark property
    public int Getpassmark()
    {
        return this._passmark;
    }
}

答案 25 :(得分:1)

属性用于公开字段。它们使用访问器(set,get),通过访问器可以读取,写入或操作私有字段的值。

属性未命名存储位置。相反,它们具有读取,写入或计算其值的访问器。

使用属性我们可以对字段上设置的数据类型进行验证。

例如,我们有一个私有整数字段年龄,我们应该允许正值,因为年龄不能为负。

我们可以使用getter和setter以及使用属性以两种方式执行此操作。

 Using Getter and Setter

    // field
    private int _age;

    // setter
    public void set(int age){
      if (age <=0)
       throw new Exception();

      this._age = age;
    }

    // getter
    public int get (){
      return this._age;
    }

 Now using property we can do the same thing. In the value is a key word

    private int _age;

    public int Age{
    get{
        return this._age;
    }

    set{
       if (value <= 0)
         throw new Exception()
       }
    }

Auto Implemented属性如果我们在get和set访问器中没有逻辑,我们可以使用自动实现的属性。

当您自动实现属性编译时,会创建一个只能通过get和set访问器访问的私有匿名字段

public int Age{get;set;}

抽象属性 抽象类可以具有抽象属性,该属性应该在派生类

中实现
public abstract class Person
   {
      public abstract string Name
      {
         get;
         set;
      }
      public abstract int Age
      {
         get;
         set;
      }
   }

// overriden something like this
// Declare a Name property of type string:
  public override string Name
  {
     get
     {
        return name;
     }
     set
     {
        name = value;
     }
  }

我们可以私下设置一个属性 在这里我们可以私下设置auto属性(在类中设置)

public int MyProperty
{
    get; private set;
}

您可以使用此代码实现相同功能。在此属性集功能不可用,因为我们必须直接将值设置为字段。

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}

答案 26 :(得分:1)

想一想:你有一个房间和一扇门进入这个房间。如果你想检查谁进入并保护你的房间,那么你应该使用属性,否则他们不会成为任何门,每个人都很容易进入任何监管

class Room {
   public string sectionOne;
   public string sectionTwo;
}

Room r = new Room();
r.sectionOne = "enter";

人们很容易进入sectionOne,没有任何检查

class Room 
{
   private string sectionOne;
   private string sectionTwo;

   public string SectionOne 
   {
      get 
      {
        return sectionOne; 
      }
      set 
      { 
        sectionOne = Check(value); 
      }
   }
}

Room r = new Room();
r.SectionOne = "enter";

现在你检查了这个人并且知道他是否有邪恶的东西

答案 27 :(得分:1)

绝大多数情况下,它将是您访问的属性名称而不是变量名称(字段)原因是它被认为是.NET和C#中的良好实践特别是保护类中的每一段数据,无论是实例变量还是静态变量(类变量),因为它与类相关联。

使用相应的属性保护所有这些变量,这些属性允许您定义设置和获取 accessors,并在操作这些数据时执行验证等操作。

但是在其他情况下,例如Math class(系统名称空间),在类中内置了一些静态属性。其中一个是数学常数PI

例如。 Math.PI

由于PI是一个定义明确的数据,因此我们不需要拥有PI的多个副本,它总是具有相同的值。因此,静态变量有时用于在类的对象之间共享数据,但它们也常用于常量信息,其中您只需要一个数据的一个副本。

答案 28 :(得分:1)

字段是类中的变量。字段是您可以通过使用访问修饰符封装的数据。

属性与字段类似,它们定义状态和与对象关联的数据。

与字段不同,属性具有特殊的语法来控制人如何读取数据和写入数据,这些称为get和set运算符。设置逻辑通常可用于进行验证。

答案 29 :(得分:1)

尽管字段和属性看起来很相似,但它们是2种完全不同的语言元素。

  1. 字段是在类级别存储数据的唯一机制。字段在概念上是类范围内的变量。如果要将一些数据存储到类(对象)的实例中,则需要使用字段。别无选择。尽管属性无法存储任何数据,但看起来它们可以存储数据。见下面。

  2. 另一方面,属性从不存储数据。它们只是一对方法(get和set),可以用类似于字段的方式在语法上进行调用,在大多数情况下,它们是访问(用于读取或写入)字段,这是造成某些混乱的根源。但是由于属性方法是常规C#方法(有一些限制,例如固定原型),所以常规方法可以执行常规方法。这意味着它们可以具有1000行代码,可以引发异常,调用其他方法,甚至可以是虚拟的,抽象的或覆盖的。使属性与众不同的原因是,C#编译器将一些额外的元数据存储到程序集中,这些元数据可用于搜索特定属性-广泛使用的功能。

获取和设置属性方法具有以下原型。

PROPERTY_TYPE get();

void set(PROPERTY_TYPE value);

因此,这意味着可以通过定义一个字段和2种相应方法来“模拟”属性。

class PropertyEmulation
{
    private string MSomeValue;

    public string GetSomeValue()
    {
        return(MSomeValue);
    }

    public void SetSomeValue(string value)
    {
        MSomeValue=value;
    }
}

对于不支持属性的编程语言(例如标准C ++),典型的是这种属性仿真。在C#中,您应该始终首选属性作为访问字段的方式。

因为只有字段可以存储数据,所以意味着包含更多字段的类将消耗更多此类内存对象。另一方面,在类中添加新属性不会使此类对象更大。这是示例。

class OneHundredFields
{
        public int Field1;
        public int Field2;
        ...
        public int Field100;
}

OneHundredFields Instance=new OneHundredFields() // Variable 'Instance' consumes 100*sizeof(int) bytes of memory.

class OneHundredProperties
{
    public int Property1
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    public int Property2
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    ...

    public int Property100
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }
}

OneHundredProperties Instance=new OneHundredProperties() // !!!!! Variable 'Instance' consumes 0 bytes of memory. (In fact a some bytes are consumed becasue every object contais some auxiliarity data, but size doesn't depend on number of properties).

尽管属性方法可以执行任何操作,但在大多数情况下,它们用作访问对象字段的一种方式。如果要使其他类可以访问该字段,则可以通过两种方法进行。

  1. 将字段设为公开-不建议。
  2. 使用属性。

这是一个使用公共字段的类。

class Name
{
    public string FullName;
    public int YearOfBirth;
    public int Age;
}

Name name=new Name();

name.FullName="Tim Anderson";
name.YearOfBirth=1979;
name.Age=40;

尽管从设计的角度来看,代码是完全有效的,但它也有一些缺点。由于字段可以读写,因此不能阻止用户写入字段。您可以应用readonly关键字,但是通过这种方式,您只需要在构造函数中初始化只读字段。而且,没有什么可以阻止您将无效值存储到字段中。

name.FullName=null;
name.YearOfBirth=2200;
name.Age=-140;

该代码有效,尽管所有分配都不合逻辑,但它们将被执行。 Age的值为负,YearOfBirth的日期很远并且与Age不对应,并且FullName为null。使用字段,您无法阻止class Name的用户犯此类错误。

这是具有可解决这些问题的属性的代码。

class Name
{
    private string MFullName="";
    private int MYearOfBirth;

    public string FullName
    {
        get
        {
            return(MFullName);
        }
        set
        {
            if (value==null)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MFullName=value;
        }
    }

    public int YearOfBirth
    {
        get
        {
            return(MYearOfBirth);
        }
        set
        {
            if (MYearOfBirth<1900 || MYearOfBirth>DateTime.Now.Year)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MYearOfBirth=value;
        }
    }

    public int Age
    {
        get
        {
            return(DateTime.Now.Year-MYearOfBirth);
        }
    }

    public string FullNameInUppercase
    {
        get
        {
            return(MFullName.ToUpper());
        }
    }
}

类的更新版本具有以下优点。

    检查
  1. FullNameYearOfBirth的无效值。
  2. Age不可写。从YearOfBirth和当前年份开始调用。
  3. 新属性FullNameInUppercaseFullName转换为大写。这是一个关于属性用法的人为设计示例,其中属性通常用于以更适合用户的格式显示字段值-例如,使用DateTime格式的特定数字的当前语言环境。

此外,可以将属性定义为虚拟的或覆盖的-仅因为它们是常规的.NET方法。此类规则适用于常规方法。

C#还支持索引器,这些索引器是在属性方法中具有索引参数的属性。这是示例。

class MyList
{
    private string[]                 MBuffer;

    public MyList()
    {
        MBuffer=new string[100];
    }

    public string this[int Index]
    {
        get
        {
            return(MBuffer[Index]);
        }
        set
        {
            MBuffer[Index]=value;
        }
    }
}

MyList   List=new MyList();

List[10]="ABC";
Console.WriteLine(List[10]);

由于C#3.0允许您定义自动属性。这是示例。

class AutoProps
{
    public int Value1
    {
        get;
        set;
    }

    public int Value2
    {
        get;
        set;
    }
}

即使class AutoProps仅包含属性(或看起来像),它也可以存储2个值,并且此类的对象大小等于sizeof(Value1)+sizeof(Value2) = 4 + 4 = 8字节。

原因很简单。定义自动属性时,C#编译器会生成自动代码,其中包含隐藏字段和带有属性方法的属性,该属性方法可访问此隐藏字段。这是编译器生成的代码。

这是 ILSpy 从编译的程序集生成的代码。该类包含生成的隐藏字段和属性。

internal class AutoProps
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value1>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value2>k__BackingField;

    public int Value1
    {
        [CompilerGenerated]
        get
        {
            return <Value1>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value1>k__BackingField = value;
        }
    }

    public int Value2
    {
        [CompilerGenerated]
        get
        {
            return <Value2>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value2>k__BackingField = value;
        }
    }
}

因此,如您所见,编译器仍然使用字段来存储值-因为字段是将值存储到对象中的唯一方法。

因此,您可以看到,尽管属性和字段的用法语法相似,但它们是非常不同的概念。即使您使用自动属性或事件,隐藏字段也由编译器生成,其中真实数据位于存储。

如果您需要使外部用户(您的类的用户)可以访问某个字段值,请不要使用公共或受保护的字段。字段始终应标记为私有。属性使您可以进行值检查,格式设置,转换等,并且通常可以使您的代码更安全,更易读且可扩展,以备将来修改之用。

答案 30 :(得分:1)

here清楚地说明了差异。不过,仅作总结和强调:

字段被封装在类内部以进行内部操作,而属性可以用于将类暴露给外部世界,以及共享链接中显示的其他内部操作。此外,如果要加载某些方法或基于用户的控件根据特定字段的值,该属性将为您完成此操作:

例如:

您可以在asp.net页内的用户控件下方运行,只需在aspx页中为控件的ID属性赋值即可,如下所示:

useMeId.Id=5 ---call the property of user control "UseMe.ascx"

UseMe.ascx

<%@ Register Src=~/"UseMe.ascx" TagPrefix="uc" TagName="UseMe" %>
<uc:UseMe runat="Server" id="useMeId" />

UseMe.ascx.cs

private int currentId;

public int Id
   {
      get
      {
         return currentId;
      }
      set
      {
         currentId = value;
       LoadInitialData(currentId);
      }
   }
Private void LoadinitialData(int currentIdParam)
{
//your action

}

答案 31 :(得分:0)

其他信息: 默认情况下,get和set访问器与属性本身一样可访问。 您可以通过对它们应用更严格的访问修饰符来单独控制/限制访问者可访问性(对于获取和设置)。

示例:

public string Name
{
    get
    {
        return name;
    }
    protected set
    {
        name = value;
    }
}

此处仍然公开访问get(因为属性是公共的),但set受保护(更受限制的访问说明符)。