为什么我需要通过公共财产公开的私人领域?

我主要来自Java世界。 所以,C#属性看起来不错。

我知道使用C#3.0或更高版本我可以使用自动属性。 我更喜欢它:)。

我的问题是关于一个(可能更旧的)代码,我可以看到这个:

private int age; public int Age { get { return age; } set { age = value; } } 

为什么我需要私人领域时代? 我真的藏在这里的是什么?

编辑:

我完全理解吸气剂和固定剂的必要性。 我提到我是从Java世界来的,并且一直这样做。

我知道C#3.0或以上的自动属性是合成糖。 但也许我的问题有一个更简单的答案。 这是否意味着(吼叫C#3.0)该财产没有任何价值。 那么它必须从其他领域获得价值吗?

较旧版本的C#没有自动属性,因此您必须声明属性所执行的变量,如示例中所示。 这些天,相同的代码可以表示为:

 public int Age { get; set; } 

我认为这可以回答你的问题。 但是,如果你问“为什么不公开int Age;并且让程序员直接在字段上设置值?”,那么:

首先要记住的是,属性访问器被编译成方法。 这意味着它具有与读/写到类成员​​变量不同的ABI,即使它在语法上看起来与您拥有的相同:

 class Fu { public int Age; } 

因此,这意味着,如果在某个时刻,您需要添加一些Age字段已更改的通知 – 如果您正在使用属性,则可以轻松地将此通知逻辑添加到属性设置器而不会破坏ABI。

 public int Age { get { return age; } set { age = value; NotifySomeOtherCode (); } } 

如果您从公共字段开始,然后将其更改为属性将更改ABI,这对可能取决于您的程序集的任何程序都是不利的。 所以最好从属性开始。

希望我有意义……

旧版本的C#编译器不支持自动属性。

上面的代码或多或少与此相同(假设该字段实际上从未直接使用过):

 public int Age { get; set; } 

在这种情况下,您不需要它。 但是,如果您需要在setter或getter中执行任何其他操作,则自动属性将不起作用 – 您将需要私有字段进行操作。

沼泽标准的答案是“封装年龄存储方式和地点的实施细节”。

出于检索目的,一个更现实的例子可能是,有一天,您可能希望以一种意味着直接访问不太好的方式访问该值。 例如,如果它是您可能在其他地方缓存的值,或者它是计算值。

在封装设置过程方面,这意味着您可以将一些模型级validation嵌入到setter中; 如果有人试图设置概念上无效的值,您可以抛出IllegalArgumentException并拒绝它。

在这些情况下,封装意味着您不必更改所有现有代码,因为您必须将值包装在某些内容中。

C#中的自动属性在编译时,在function上与上面的代码完全相同。 编译器为您生成一个支持字段。

所以你确实需要一些支持属性的东西 – 一个字段或一些代码 – 它只是通过自动属性的快捷方式为你照顾。

属性只是编写一对getset方法的好方法。 在Java中你会这样做:

 private int age; public int getAge() { return age; } public void setAge(int value) { age = value; } 

您需要私有字段来存储某个年龄 – getAge和setAge只是方法。

这同样适用于3.0之前版本的C#:

 private int age; public int Age { get { return age; } set { age = value; } } 

这是一个get和set方法,很好地配对,所以你可以写x.Age = 21而不是x.setAge(21)

使用自动属性,C#编译器会为您生成私有字段(但它仍然存在!):

 public int Age { get; set; } 

自动属性的好处是您不必再自己手动创建支持字段。

手动版本的好处是,您可以为get和set方法添加其他逻辑,例如,参数validation:

 private int age; public int Age { get { return age; } set { if (value < 0) throw new ArgumentException(); age = value; } } 

也许你想稍后改变setter或getter的行为。 例如记录值是从外部改变的。 对于没有属性的公共字段,这是不可能的

  private int age; public int Age { get { return age; } set { age = value; Log("value of age changed"); } } 

对于公共字段age ,您必须在更改年龄值的代码中随处记录此内容。

在这种情况下,您不会隐藏任何内容,但它可以让您自由地在以后向您的私有字段添加get / set逻辑。 因此,使用该物业的任何人都不会注意到未来的差异。

在简单的情况下没有。 但是,如果这两种方法中的任何一种的实现都需要额外的代码,那么就可以更容易地维护类的接口。

例如,如果您需要向setter添加更改事件。

  public int Age { get { return age; } set { if ( age != value) { age = value; OnAgeChanged(); } } } 

您可以使用属性执行此操作,而不是破坏客户端代码。 一个领域没有这个优势。

使用自动属性,您无需执行此操作。 它没有任何问题,但有了自动属性,你仍然会拥有你的财产签名 ,这是重要的事情。 在自动属性之前,您必须拥有属性的支持字段。 只要您具有自动属性,您可以稍后将其更改为具有显式支持字段的格式,并且签名保持不变。

但是,它没有任何问题。 除了公约越来越多地称为私人支持领域“_age”。

(我假设您知道为什么要拥有一个属性 ,无论是否自动,而不是公共字段 。原因是如果您将表单公共字段更改为公共属性,则该对象具有不同的签名,因此最安全的是刚开始关闭财产,即使没有额外的逻辑。)

Getters和Setter是其他类与之交互的公共接口。 在复杂系统中,您通常最终会在getter和setter中进行validation和其他工作。

私人领域供内部使用。 如果您需要更改类中的值但绕过所有额外的工作,您将更改私有变量。