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

1032 c# field properties

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

Cor*_*ory 890

属性公开字段.字段应该(几乎总是)保持对类的私有,并通过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;} 
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

dan*_*ain 244

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

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

Han*_*ken 160

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

  • 这个答案和下面的答案都是正确的。投票最多的 2 个帖子没有回答问题。问题是“有什么区别......”,但投票最多的答案回答“我不是告诉你有什么区别,而是告诉你应该如何工作” (7认同)
  • 好奇这种罕见的情况会是什么! (3认同)

Chr*_*ris 95

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

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

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

Jeh*_*hof 49

使用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);
   }
 }
}
Run Code Online (Sandbox Code Playgroud)

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

Sar*_*avu 43

因为他们中许多人与技术的利弊解释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;
           }
       }       
    } 
}
Run Code Online (Sandbox Code Playgroud)

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;
        }
   } 
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
        }
   }
Run Code Online (Sandbox Code Playgroud)

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

小智 31

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

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

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


Tim*_*y_A 13

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

  1. 字段是如何在类级别存储数据的唯一机制。字段在概念上是类范围内的变量。如果要将某些数据存储到类(对象)的实例中,则需要使用字段。没有其他选择。即使属性不能存储任何数据,但看起来他们能够这样做。见下文。

  2. 另一方面,属性从不存储数据。它们只是成对的方法(get 和 set),它们可以在语法上以与字段类似的方式调用,并且在大多数情况下它们访问(读取或写入)字段,这是一些混淆的根源。但是因为属性方法是(有一些限制,比如固定原型)常规的 C# 方法,它们可以做任何常规方法可以做的事情。这意味着它们可以有 1000 行代码,可以抛出异常,调用其他方法,甚至可以是虚拟的、抽象的或覆盖的。属性的特殊之处在于,C# 编译器将一些额外的元数据存储到可用于搜索特定属性的程序集中——广泛使用的功能。

Get 和 set 属性方法具有以下原型。

PROPERTY_TYPE get();

void set(PROPERTY_TYPE value);
Run Code Online (Sandbox Code Playgroud)

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

class PropertyEmulation
{
    private string MSomeValue;

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

    public void SetSomeValue(string value)
    {
        MSomeValue=value;
    }
}
Run Code Online (Sandbox Code Playgroud)

这种属性模拟对于不支持属性的编程语言来说是典型的——比如标准 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).
Run Code Online (Sandbox Code Playgroud)

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

  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;
Run Code Online (Sandbox Code Playgroud)

虽然代码完全有效,但从设计的角度来看,它有几个缺点。由于字段既可以读取也可以写入,因此您无法阻止用户写入字段。您可以应用readonly关键字,但这样,您必须仅在构造函数中初始化只读字段。更重要的是,没有什么可以阻止您将无效值存储到您的字段中。

name.FullName=null;
name.YearOfBirth=2200;
name.Age=-140;
Run Code Online (Sandbox Code Playgroud)

代码是有效的,所有的赋值都会被执行,尽管它们是不合逻辑的。Age有一个负值,YearOfBirth在未来很远,不对应于年龄,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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  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]);
Run Code Online (Sandbox Code Playgroud)

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

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

    public int Value2
    {
        get;
        set;
    }
}
Run Code Online (Sandbox Code Playgroud)

即使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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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


Sco*_*ski 12

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

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


Run*_*tad 11

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


Bri*_*sen 10

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

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

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

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

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

  • 属性不应该有副作用。即使调试器也假设它可以安全地评估它们。 (2认同)

小智 7

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

例如,如果我有名为"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";
    }
}
Run Code Online (Sandbox Code Playgroud)


Joe*_*nta 6

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

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

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

public void TransformPoint(ref double x, ref double y);
Run Code Online (Sandbox Code Playgroud)

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

System.Windows.Point[] points = new Point[1000000];
Initialize(points);
Run Code Online (Sandbox Code Playgroud)

我认为这是最快的方法,因为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;
}
Run Code Online (Sandbox Code Playgroud)

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

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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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


Gur*_*epS 5

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

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

非常有用的功能。


Moe*_*sko 5

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

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

get { return _afield; }
set { _afield = value; }
Run Code Online (Sandbox Code Playgroud)

他们的理由是,如果需要的话,公共领域可以在未来转化为财产。当时我觉得有点奇怪。从这些帖子来看,似乎也没有多少人同意。你可能会说些什么来尝试改变事情?

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


Bra*_*iat 5

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


Vas*_*ikh 5

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

  class SomeClass
  {
     int numbera; //Field

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

  }
Run Code Online (Sandbox Code Playgroud)