1374

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

4

33 回答 33

1188

属性公开字段。字段应该(几乎总是)对类保持私有,并通过 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 指出 Properties 不需要封装字段,它们可以对其他字段进行计算,或用于其他目的。

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

于 2008-11-17T08:44:18.813 回答
302

面向对象的编程原则说,一个类的内部工作应该对外界隐藏。如果您公开一个字段,您实质上就是在公开该类的内部实现。因此,我们用属性(或 Java 中的方法)包装字段,使我们能够在不破坏代码的情况下更改实现,这取决于我们。看到我们可以在属性中放置逻辑也允许我们在需要时执行验证逻辑等。C# 3 具有可能令人困惑的自动属性概念。这使我们可以简单地定义属性,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
}
于 2008-11-17T09:05:28.567 回答
196

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

于 2008-11-17T13:44:00.597 回答
109

我会给你几个例子,说明使用可能使齿轮转动的属性:

  • 延迟初始化如果您有一个对象的属性加载起来很昂贵,但在代码的正常运行中没有被访问那么多,您可以通过该属性延迟它的加载。这样,它只是坐在那里,但是当另一个模块第一次尝试调用该属性时,它会检查底层字段是否为空 - 如果是,它会继续加载它,调用模块不知道。这可以大大加快对象初始化。
  • Dirty Tracking:我实际上是从StackOverflow 上的问题中了解到的。当我有很多在运行期间值可能发生变化的对象时,我可以使用该属性来跟踪它们是否需要保存回数据库。如果一个对象的单个属性没有改变,IsDirty 标志不会被触发,因此在决定需要返回数据库的内容时,保存功能将跳过它。
于 2008-11-17T14:27:54.750 回答
65

使用属性,您可以在属性值更改(又名 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(){       
     NameChanging?.Invoke(this,EventArgs.Empty);       
 }

 private void OnNameChanged(){
     NameChanged?.Invoke(this,EventArgs.Empty);
 }
}
于 2009-06-26T06:32:18.790 回答
50

Properties由于他们中的许多人已经解释了and的技术优缺点Field,是时候进入实时示例了。

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

考虑 和 的dataTable.Rows.Count情况dataTable.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 中使用过。它的属性显示在PropertyGridlikeText等中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的属性,但不会显示。为什么???因为 Properties 可以接受Attributes。如果 where为假,则不会显示。NameTextSomeProperty[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中只能使用Properties

Binding Source帮助我们减少代码行数。Fields不被接受BindingSource。我们应该使用Properties它。

5.调试模式

考虑我们Field用来保存一个值。在某些时候,我们需要调试并检查该字段的值在何处变为空。代码行数超过 1000 行的地方就很难做到。这种情况下我们可以使用Property并且可以在里面设置调试模式Property

   public string Name
   {
        // Can set debug mode inside get or set
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   }
于 2014-10-06T06:59:17.637 回答
45

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

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

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

于 2013-09-12T14:18:31.537 回答
18

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

  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).

尽管属性方法可以做任何事情,但在大多数情况下,它们用作访问对象字段的一种方式。如果您想让其他类可以访问一个字段,您可以通过 2 种方式来完成。

  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为空。使用字段,您无法阻止用户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. 新属性FullNameInUppercase转换FullName为大写。这是一个有点人为的属性使用示例,其中属性通常用于以更适合用户的格式呈现字段值 - 例如在特定数字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;
        }
    }
}

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

如您所见,尽管属性和字段具有相似的用法语法,但它们是非常不同的概念。即使您使用自动属性或事件 - 隐藏字段也是由存储真实数据的编译器生成的。

如果您需要使外部世界(您班级的用户)可以访问字段值,请不要使用公共或受保护字段。字段应始终标记为私有。属性允许您进行值检查、格式化、转换等,并且通常使您的代码更安全、更具可读性和更可扩展以供将来修改。

于 2019-06-26T13:24:09.430 回答
16

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

如果您编写一个专为广泛使用而设计的类库(例如被数百万人使用的 .NET Framework),这可能是个问题。但是,如果您正在编写一个在小型代码库(例如 <= 50 K 行)内部使用的类,这真的没什么大不了的,因为没有人会受到您的更改的不利影响。在这种情况下,它真的只是归结为个人喜好。

于 2008-11-17T10:09:51.540 回答
15

属性支持非对称访问,即您可以拥有一个getter 和一个setter,或者只是两者之一。同样,属性支持 getter/setter 的单独可访问性。字段始终是对称的,即您始终可以获取和设置值。例外情况是只读字段,初始化后显然无法设置。

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

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

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

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

于 2008-11-17T11:40:22.403 回答
13

在后台,属性被编译成方法。所以一个Name属性被编译成get_Name()and set_Name(string value)。如果您研究编译的代码,您可以看到这一点。所以在使用它们时会有(非常)小的性能开销。通常,如果您将字段公开到外部,您将始终使用属性,如果您需要验证值,您通常会在内部使用它。

于 2008-11-17T10:51:52.457 回答
7

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

例如,如果我有名为“id”和“name”的变量,它们是私有的,但可能存在该变量需要在类外进行读/写操作的情况。在那种情况下,属性可以帮助我根据为属性定义的获取/设置来读取/写入该变量。一个属性可以是只读/只写/读写两者。

这是演示

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";
    }
}
于 2013-12-29T06:48:45.900 回答
6

这里的第二个问题,“什么时候应该使用一个字段而不是一个属性?”,在另一个答案中只是简单地提到了这个问题,也有点像这个,但没有太多细节。

一般来说,所有其他答案都是关于良好设计的:更喜欢公开属性而不是公开字段。虽然你可能不会经常发现自己说“哇,想象一下如果我把它变成一个字段而不是一个属性会变得多么糟糕”,但很少想到你会说“哇,感谢上帝,我在这里使用了一个字段而不是一个属性。”

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

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

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

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

这是我认为最快的方法,因为XY是属性:

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);
}

我自己进行了一些测量,带有字段的版本大约需要 61% 的时间作为带有属性的版本(.NET 4.6、Windows 7、x64、发布模式、未附加调试器)。方法越昂贵TransformPoint,差异就越不明显。要自己重复这一点,请在第一行注释掉并且不注释掉的情况下运行。

即使上述情况没有性能优势,也有其他地方能够使用 ref 和 out 参数可能是有益的,例如在调用InterlockedVolatile系列方法时。 注意:如果这对您来说是新的,Volatile 基本上是一种获得volatile关键字提供的相同行为的方法。因此,就像它一样volatile,它并没有像它的名字所暗示的那样神奇地解决所有线程安全问题。

我绝对不想看起来像是在提倡你去“哦,我应该开始公开字段而不是属性”。关键是,如果您需要在带有“ref”或“out”参数的调用中经常使用这些成员,特别是在可能是一个简单的值类型的东西上,它不太可能需要任何属性的增值元素,可以提出论据。

于 2015-08-15T14:07:57.877 回答
4

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

于 2008-11-17T09:44:55.803 回答
4

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

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

真正有用的功能。

于 2008-11-17T10:46:29.597 回答
4

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

我曾经在一个推荐的做法是使用公共字段而不是属性的地方工作,而等效的属性 def 只是在访问一个字段,如下所示:

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

他们的理由是,如果需要,将来可以将公共字段转换为属性。当时我觉得有点奇怪。从这些帖子来看,这里似乎也没有多少人会同意。你可能会说什么来尝试改变事情?

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

于 2009-06-26T06:13:37.260 回答
4

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

于 2013-11-01T07:04:05.633 回答
4

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

  class SomeClass
  {
     int numbera; //Field

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

  }
于 2015-08-10T20:03:19.933 回答
4

我对字段的设计是字段只需要由其父级修改,因此是类。结果变量变为私有,然后能够授予读取外部类/方法的权限,我只使用 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;
 }
}
于 2016-12-09T09:46:54.247 回答
4

基本和一般的区别是:

字段

  • 始终给予 get 和 set 访问权限
  • 不能引起副作用(抛出异常、调用方法、更改字段,除了被获取/设置的字段等)

特性

  • 不总是同时授予 get 和 set 访问权限
  • 引起副作用
于 2019-06-15T17:32:24.903 回答
3

属性封装字段,从而使您能够对要设置或检索的值执行额外的处理。如果您不对字段值进行任何预处理或后处理,则使用属性通常是矫枉过正的。

于 2008-11-17T10:05:18.243 回答
3

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

于 2013-12-16T15:03:51.493 回答
3

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

于 2015-04-01T01:30:10.473 回答
3

当您有一个“汽车”课程时。属性是颜色,形状..

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

于 2015-04-01T03:09:23.263 回答
3

来自维基百科——面向对象的编程

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

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

于 2015-08-26T10:58:37.543 回答
3

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

例子:

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

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

于 2017-01-16T17:42:16.467 回答
3

想一想:你有一个房间和一扇门可以进入这个房间。如果您想检查谁是如何进入并保护您的房间,那么您应该使用属性,否则它们将不是任何门,并且每个人都可以轻松进入而没有任何规定

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";

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

于 2017-06-26T14:48:33.940 回答
3

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

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

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

于 2018-10-24T07:57:42.100 回答
2

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

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

我们为什么要使用属性?

将类字段公开并公开是有风险的,因为您无法控制分配和返回的内容。

为了通过一个例子清楚地理解这一点,让我们以一个有 ID、passmark、name 的学生班级为例。现在在这个例子中,公共领域有一些问题

  • ID 不应为 -ve。
  • 名称不能设置为空
  • 通过标记应该是只读的。
  • 如果缺少学生姓名,则不应返回姓名。

为了消除这个问题,我们使用 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;
    }
}
于 2016-03-01T08:53:25.230 回答
2

属性用于公开字段。他们使用访问器(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()
       }
    }

自动实现的属性如果我们不在 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;
     }
  }

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

public int MyProperty
{
    get; private set;
}

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

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}
于 2017-06-14T17:37:21.690 回答
2

在绝大多数情况下,它将是您访问的属性名称,而不是变量名称(字段),原因是它在 .NET 和 C# 中被认为是一种很好的做法,尤其是在保护类中的每条数据方面,无论是实例变量还是静态变量(类变量),因为它与一个类相关联。

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

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

例如。数学.PI

并且因为 PI 是一条定义明确的数据,我们不需要有多个 PI 副本,它始终是相同的值。因此,静态变量有时用于在类的对象之间共享数据,但也常用于只需要一份数据副本的常量信息。

于 2018-02-27T11:33:15.277 回答
1

区别在这里清楚地解释了。但是,只是为了总结和强调:

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

例如:

您可以通过简单地为您的 aspx 页面中的 Id preperty 分配一个值来在您的 asp.net 页面中的用户控件下方运行,如下所示:

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

使用Me.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

}
于 2020-04-21T10:05:57.437 回答
0

阅读所有答案后,我没有找到有关并发访问的答案。

假设您有一个可以异步访问的 API 端点,并且您正在使用静态字段来存储数据,并且完全需要对静态字段具有独占访问权限。

要重现此示例,您将需要进行负载测试以同时对端点进行大量访问。

当使用静态 int 计数器字段时,端点在两次或多次访问中获得相同的值。 在此处输入图像描述

使用静态 int 计数器属性时,端点处理并发并始终获取计数器的新值。

在此处输入图像描述

这根本不能回答问题,但是在使用其中一种时必须考虑到这种行为。

于 2022-02-14T11:13:03.360 回答