2010-07-22 78 views
159

我才意识到,在C#属性结构还可以与私人访问修饰符使用:是否有任何理由在C#中使用私有属性?

private string Password { get; set; } 

尽管这在技术上是有趣的,我无法想象我会用它,因为一个私人领域涉及即使少仪式

private string _password; 

,当我会永远需要是我无法想象能够内部得到但不设置设置但不得到私有字段:

private string Password { get; } 

private string Password { set; } 

但也许有一个用例与嵌套/继承类或可能在哪里一个get/set可能包含逻辑,而不仅仅是回馈属性的值,尽管我倾向于保持属性的严格性,并让显式方法执行任何逻辑操作。 GetEncodedPassword()

有没有人在C#中使用私有属性是出于任何原因,还是仅仅是那些技术上可行但很少使用的实际代码构造?

附录

尼斯的答案,通过他们读我宰杀这些用途为私人性质:

  • 当私人领域需要延迟加载
  • 当私人领域需要额外的逻辑或计算值
  • 由于专用字段可能难以调试
  • 为了“向您自己提交合同”
  • 在内部转换/简化公开的属性序列化
  • 包装全局变量的一部分,你的类
+3

“私人字符串密码{get;}”甚至不合法的C#。它不会编译。 – 2010-07-22 15:17:53

+2

@eric true,它会得到错误“... Password.get'必须声明一个实体,因为它没有标记为抽象或外部自动实现的属性必须同时定义get和set访问器。我只是假定它会工作,因为我使用'公共字符串密码{得到{返回_密码;经常。 – 2010-07-22 15:30:18

+0

私人财产鼓励的技术是*自封装* - 请参阅:http://sourcemaking.com/refactoring/self-encapsulate-field – LBushkin 2010-07-22 18:30:10

回答

151

我使用它们,如果我需要缓存一个值,并希望延迟加载它。

private string _password; 
private string Password 
{ 
    get 
    { 
     if (_password == null) 
     { 
      _password = CallExpensiveOperation(); 
     } 

     return _password; 
    } 
} 
+0

+1这也是我的标准使用!我还喜欢稍后以@Reed Copsey的方式添加额外逻辑的能力。 – 2010-07-22 15:21:48

+0

+1同样在这里... – 2010-07-22 16:36:57

+13

一个很好的常见模式是'return _password ?? (_password = CallExpensiveOperation());' – Marc 2010-07-22 23:20:08

4

内使用我现在然后用它们每一个。当您可以轻松地在属性中放置断点或者可以添加日志记录语句时,它们可以更容易地进行调试。

如果以后需要更改某些数据的类型方式或如果你需要使用反射。

+0

同上;如果在get/set中涉及逻辑,我有时可能会使用私有或受保护的属性。它通常取决于多少逻辑:我将在属性中执行简单的逻辑,我通常会使用辅助函数的很多逻辑。无论代码如何最可维护。 – TechNeilogy 2010-07-22 14:57:22

32

也许有一个用例的嵌套/继承的类或者是其中的get/set可能包含的逻辑,而不是只给后面的属性值

我个人使用,甚至当我不需要属性的getter或setter的逻辑。使用属性即使是私有属性也可以帮助您确定未来的代码,以便稍后将逻辑添加到getter中(如果需要)。

如果我觉得一个属性最终可能需要额外的逻辑,我有时会将它包装到一个私有属性中而不是使用一个字段,这样我就不必在以后更改我的代码。


在一个半相关的情况下(虽然比你的问题不同),我非常频繁使用私有制定者的公共属性:

public string Password 
{ 
    get; 
    private set; 
} 

这给你一个公共的getter,但保持二传手私人的。

+0

+1有道理:“如果我觉得一个属性最终可能需要额外的逻辑,我有时会将它包装到一个私有属性中,而不是使用一个字段,这样我就不必稍后更改我的代码。” – 2010-07-22 15:00:42

+5

private setters <3 – Earlz 2010-07-22 15:38:51

2

通常的做法是只使用get/set方法修改成员,甚至是私有成员。现在,背后的逻辑就是让你知道你的get/set总是以特定的方式行事(例如,引发事件),这似乎没有道理,因为这些将不会包含在属性方案中。但老习惯很难消除。

2

当存在与属性集合相关的逻辑或获取(认为延迟初始化)并且该属性在类中的一些地方使用时,这是非常有意义的。

如果它只是一个直接的后盾领域?没有什么可以成为一个很好的理由。

11

唯一的一个用法,我能想到的

private bool IsPasswordSet 
{ 
    get 
    { 
     return !String.IsNullOrEmpty(_password); 
    } 
} 
+0

+1为从其他私有变量计算的有用类属性 – 2010-07-22 15:43:29

+0

为什么不使用私有方法 'private bool IsPasswordSet() { return!String。IsNullOrEmpty(_password); }' – Roman 2016-09-21 16:05:48

5

的属性和字段是不是一对一的。一个属性是关于一个类的接口(不管是在谈论它的公共接口还是内部接口),而一个属性是关于类的实现。不应该将属性视为暴露字段的方式,它们应该被视为暴露类的意图和目的的一种方式。

就像您使用属性向您的消费者提供关于您班级的组成部分的合同一样,您也可以出于非常类似的原因向您自己提供合同。所以是的,我确实使用私有财产。有时候私有财产会隐藏实现细节,例如延迟加载,属性实际上是多个领域和方面的聚合,或者每次调用都需要虚拟实例化财产(认为DateTime.Now)。在班级的后端,甚至在你自己身上执行这个任务也是有意义的。

+0

+1:“你也可以出于非常类似的原因向你自己提供合同”很有道理 – 2010-07-22 15:11:39

16

懒惰初始化是一个可以整洁的地方,例如,

private Lazy<MyType> mytype = new Lazy<MyType>(/* expensive factory function */); 

private MyType MyType { get { return this.mytype.Value; } } 

// In C#6, you replace the last line with: private MyType MyType => myType.Value; 

然后,你可以写:​​无处不在,而不是this.mytype.Value和封装的事实,这是在一个地方懒洋洋地实例化。

有一件令人遗憾的事情是,C#不支持将支持域作为范围映射到属性(即在属性定义中声明它)以完全隐藏它并确保它只能通过属性访问。

+2

同意它将在那里有范围方面。 – 2010-07-22 15:03:01

+5

我经常使用这种相同的技术,我也希望字段可以作用于代码体。这是一个很好的功能,但优先级低。 – 2010-07-22 15:12:04

+3

@Eric Lippert - 'accessor-declarations'中的'field-declaration'作用域在很长一段时间内在C#愿望清单中排名第一。如果你能在一些(实际)未来的版本中得到设计和实现,那么我会烤你一块蛋糕。 – 2010-07-22 17:16:54

14

私人获取唯一属性的一个很好用法是计算值。有几次,我有私人只读的属性,只是在我的类型的其他领域进行计算。它不值得一种方法,并且对其他类非常感兴趣,所以它就是私有财产。

97

这个在我的代码中的主要用法是延迟初始化,正如其他人提到的。

私有属性超过字段的另一个原因是私有属性比专用字段更容易调试。我经常想知道这样的事情:“这个领域意想不到,谁是第一个设置这个领域的调用者?”如果你可以在setter上放置一个断点并打开它,它会更容易。你可以把日志记录在那里。你可以把性能指标放在那里。您可以放入在调试版本中运行的一致性检查。

基本上,它归结为:代码比数据更强大。任何让我编写我需要的代码的技术都是很好的技术。属性不允许你在其中编写代码。

+4

你说的“代码比数据更强大吗?使用Google搜索返回指向您的引用。只是想知道,所以我可以在需要时正确引用它。 – 2011-03-24 18:30:53

+15

@Joan:我不知道。要么我做了它,要么我听到有人说出来,并且想:“哇,我应该完全偷走它,然后忘记我偷走了谁的全部。” – 2011-03-24 20:04:28

+2

谢谢埃里克。嗯,我只是相信你,因为我不想说“匿名报价”:O – 2011-03-24 20:11:09

7

我在序列化中使用它们,例如DataContractSerializer或支持此用法的protobuf-net(XmlSerializer没有)。如果您需要简化的对象序列化的一部分,它是有用的:

public SomeComplexType SomeProp { get;set;} 
[DataMember(Order=1)] 
private int SomePropProxy { 
    get { return SomeProp.ToInt32(); } 
    set { SomeProp = SomeComplexType.FromInt32(value); } 
} 
5

一件事,我做所有的时间是店里的“全局”变量/缓存到HttpContext.Current

private static string SomeValue{ 
    get{ 
    if(HttpContext.Current.Items["MyClass:SomeValue"]==null){ 
     HttpContext.Current.Items["MyClass:SomeValue"]=""; 
    } 
    return HttpContext.Current.Items["MyClass:SomeValue"]; 
    } 
    set{ 
    HttpContext.Current.Items["MyClass:SomeValue"]=value; 
    } 
} 
4

我用私人性质减少访问经常使用的子属性的代码。

private double MonitorResolution 
    { 
     get { return this.Computer.Accesories.Monitor.Settings.Resolution; } 
    } 

如果有许多子属性,这很有用。

相关问题