一个属性和一个变量有什么区别?

93

我对于理解属性(property)和变量(variable)有些疑惑。

public class ABC()
{
    public int A;
    public int B { get; set; }
}

在A和B之间的确切区别是什么?


16
FYI,“A”通常被称为字段而不是变量。 - Brian Rasmussen
https://dev59.com/NnE95IYBdhLWcg3whOHK - honibis
2
https://dev59.com/qHRB5IYBdhLWcg3wWF8H - honibis
https://dev59.com/yHM_5IYBdhLWcg3wzmrL - honibis
https://dev59.com/qHRB5IYBdhLWcg3wWF8H - Mohit Kumar
@BrianRasmussen 从C++背景来看,成员变量是很常见的术语。 是否值得斤斤计较呢? - Assimilater
8个回答

79

正如许多人指出的那样,A是一个“字段”,B是一个“属性”。

真正的问题是,你为什么要在意,以及该使用什么?

我参考了Jonathan Aneja的博客文章

(虽然它是用VB写的,但同样适用于C# ;))

那么为什么要使用属性而不是字段,有5个原因:

1. 接口中不能使用字段

通过接口无法强制要求对象的公共协定中存在一个字段,但对于属性则没有问题。

2. 验证

尽管您的应用程序目前可能不需要任何验证逻辑来设置特定值,但更改业务需求可能需要稍后插入此逻辑。此时,将字段更改为属性会破坏 API 的消费者(例如,如果有人通过反射检查您的类)。

3. 二进制序列化

如果您正在使用二进制序列化,则将字段更改为属性会破坏兼容性。顺便说一句,这是 VB10 的自动实现属性具有“可绑定”后备字段(即,您可以在代码中表达后备字段的名称)的原因之一 - 这样,如果您将自动实现属性更改为扩展属性,则仍然可以通过保持后备字段名称相同来保持序列化兼容性(在 C# 中,您被迫更改它,因为它生成具有不可绑定名称的后备字段)。

4. 许多 .NET 数据绑定基础设施绑定到属性而不是字段

我听到过对于是否这样做是好事的争论,但现实情况是它现在就是这样。 (来自我的注释:WPF 绑定适用于属性)

5. 公共字段的暴露是 FxCop 违规

由于上述原因,这是不允许的。

可能还有更多的原因。

我也想指向Jeff Atwood的博客文章,并用其中的一句话作为结论:

这里真正重要的是避免编写无关紧要的代码。而在公共变量周围添加属性包装器就是毫无意义的代码精髓。


2
然而,自动实现的属性不能用作输出参数 :/ 哎呀,C#强制我们编写毫无意义的代码。 - Assimilater
更新了第5项的文档 - CA1051:不要声明可见实例字段。https://learn.microsoft.com/en-us/visualstudio/code-quality/ca1051-do-not-declare-visible-instance-fields - Tiago Crizanto
那么,如果我们根本没有任何验证,只有 public string Name {get;set;},该怎么办呢?为什么我们要这样做,而不是只使用 public Name String;?我在多个地方看到过这种情况,但我无法理解,除了“公开字段是不好的实践”之外,还有什么其他原因使用它。在我看来,这两者之间没有区别。 - CutePoison

27

A是一个字段,B是一个属性。属性基本上是getter和setter的语法糖。你定义的类将被编译成像这样:

public class ABC()
{
    public int A;

    private int backing_B;

    public void set_B(int value)
    {
        backing_B = value;
    }

    public int get_B()
    {
        return backing_B;
    }
}
请注意,这种转换对所有C#属性都成立——对ABC.B的访问将被转换为方法调用。属性基本上提供了一个"变量"的假象,实际上只是一对巧妙伪装的方法。
这很重要,因为它允许您声明自己的get和set方法体,这些方法可以验证值或执行其他有趣的操作:
private int b;

public int B {
    get { return b; }
    set {
        if (value < 0) throw new ArgumentOutOfRangeException("value");
        b = value;
    }
}

请注意,大多数属性将使用字段存储其值。 除了字段,属性很少存在于自己的情况下。


5
在C#中,任何具有getter和setter的“变量”都被称为属性。变量没有getter和setter,这就是教科书上所说的。
我的编程讲师让我们几乎在创建Java中的每个变量上都使用getter和setter。即使是索引变量,如果它们在全局类范围内声明,他也会要求我们使用getter和setter。我认为这可能有些过度,但它确实让我写了getter和setter。
关于getter和setter的真正作用是,它们很可能不仅仅设置一个内部变量。大多数setters将执行某些类型的数据验证,以确保可以将数据设置到变量中。getter还可以检查返回的数据是否符合某些标准。
如果您的属性是私有的,而您的setter和getter是public的,技术上任何人都可以访问您的变量并像公共访问实际变量一样更改它。因此,在现实中,您应该检查数据以确保它是有效的或进行其他数据检查。
private int myVariable;
public int myVariable 
{
    get 
    { 
       return myVariable; 
    }
    set 
    {
        if (value < 0) 
        { 
           throw new Exception("This is your exception some where else in code");
        }
        myVariable = value; //remember value is something that is
                            //declared automatically
    }
}

public string FirstName { get; set; }

以上是以下写法的简写方式:
private string firstName;

public string FirstName
{
    get
    {
       //...code here
    }

    set
    {
       //...code here
    }
}

4

属性是一种简短的getter或setter。您可以向属性的setget添加逻辑,或使它们成为私有的,这意味着它们不能从外部访问,而变量始终可以访问(如果它是公共的)。


3

变量是一个可变的值。

属性是一种特殊类型的方法,可以公开访问该变量。由于它是一个方法,因此您可以在其中执行除了公开变量之外的其他操作。

根据MSDN:

Property语句引入属性声明。属性可以具有 Get 过程(只读)、Set 过程(只写)或两者兼备(读/写)。使用自动实现的属性时,可以省略 Get 和 Set 过程。有关详细信息,请参阅 自动实现属性 (Visual Basic)。

您只能在类级别上使用Property。这意味着属性的声明上下文必须是类、结构、模块或接口,不能是源文件、命名空间、过程或块。有关详细信息,请参阅 声明上下文和默认访问级别。

默认情况下,属性使用公共访问级别。可以在 Property 语句上使用访问修饰符来调整属性的访问级别,并且还可以选择将其属性过程之一调整为更严格的访问级别。


2

微软官方有一篇非常好的文章(链接如下),讲述了使用字段/变量与属性之间的区别。虽然这篇文章主要是讨论FxCop违规规则,但它清晰地定义了两者之间的区别和确切的使用指南。

以下是该文章的摘录:

字段的主要用途应该是作为实现细节。字段应该是私有或内部的,并且应该使用属性来公开。访问属性就像访问字段一样容易,而属性访问器中的代码可以随着类型特性的扩展而更改,而不会引入破坏性的更改。

Refer: https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-3.0/ms182141(v=vs.80)


0
在您的例子中,A 是类 ABC 上的公共字段,而 B 是类 ABC 上的公共属性。具体来说,B 是一个auto-implemented property。这意味着“底层实现”编译器会为您完成一些工作,并有效地将您的代码转换为:
public class ABC()
{
   private int b;

   public int A;
   public int B
   {
       get
       {
          return b;
       }
       set
       {
          b = value;
       }
   }
}

0

变量基本上是为了从类中访问值或根据分配给这些变量的修饰符进入同一类中而定义的。

当我们定义属性时,会为单个属性创建两种方法,因此会产生额外的开销,这是属性的缺点。

属性的优点是可以获取或设置类的私有变量的值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接