为什么我需要通过公共财产公开的私人领域?
我主要来自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上与上面的代码完全相同。 编译器为您生成一个支持字段。
所以你确实需要一些支持属性的东西 – 一个字段或一些代码 – 它只是通过自动属性的快捷方式为你照顾。
属性只是编写一对get和set方法的好方法。 在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和其他工作。
私人领域供内部使用。 如果您需要更改类中的值但绕过所有额外的工作,您将更改私有变量。