有没有理由在C#中使用私有属性?

Edw*_*uay 227 c# properties access-modifiers

我刚刚意识到C#属性构造也可以与私有访问修饰符一起使用:

private string Password { get; set; }
Run Code Online (Sandbox Code Playgroud)

虽然这在技术上很有意思,但我无法想象何时使用它,因为私人领域涉及更少的仪式:

private string _password;
Run Code Online (Sandbox Code Playgroud)

我无法想象什么时候我需要能够内部获取但不能设置设置但不能获得私有字段:

private string Password { get; }
Run Code Online (Sandbox Code Playgroud)

要么

private string Password { set; }
Run Code Online (Sandbox Code Playgroud)

但也许有一个嵌套/继承类的用例,或者可能是get/set可能包含逻辑而不是仅仅返回属性的值,尽管我倾向于保持属性严格简单并让显式方法做任何逻辑,例如GetEncodedPassword().

是否有人出于任何原因在C#中使用私有属性,或者它只是那些技术上可能但很少使用的实际代码构造之一?

附录

很好的答案,阅读它们我剔除了私人财产的这些用途:

  • 私有字段需要延迟加载时
  • 私有字段需要额外逻辑或计算值时
  • 由于私有字段可能难以调试
  • 为了"向自己提出合同"
  • 在内部转换/简化公开属性作为序列化的一部分
  • 包装要在类中使用的全局变量

Sha*_*owe 198

如果我需要缓存一个值并想要延迟加载它,我会使用它们.

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

        return _password;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 一个很好的常见模式是`return _password ?? (_password = CallExpensiveOperation());` (32认同)
  • 对于 C# 8,它甚至更短:`private string Password => _password ??= CallExpectiveOperation();` (12认同)
  • @Bas这不是延迟加载,因为在包含对象的构造/初始化期间而不是在首次访问属性时调用“CallExppressiveOperation();”。 (10认同)
  • +1 这也是我的标准用法!我也喜欢稍后添加额外逻辑的能力,正如 @Reed Copsey 之前提到的。 (3认同)
  • Lazy <T>怎么样? (3认同)
  • @Marc自C#6起,您甚至不必编写get和return。`private string密码=&gt; _password ?? (_password = CallExpensiveOperation());` (3认同)

Eri*_*ert 131

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

私有属性优于字段的另一个原因是私有属性比私有字段更容易调试.我经常想知道这样的事情:"这个字段是意外设置的;谁是设置这个字段的第一个调用者?" 如果你可以在setter上放一个断点然后点击它就会更容易.你可以把登录放在那里.您可以将性能指标放在那里.您可以放入在调试版本中运行的一致性检查.

基本上,它归结为:代码远比数据强大.任何让我编写我需要的代码的技术都是很好的.字段不允许您在其中编写代码,属性可以.

  • @Joan:我不知道.要么我做了,要么我听到别人说出来并且想"哇,我应该完全偷走它,然后忘记我从谁那里偷走它的一切." (21认同)
  • 你的说法是"代码远比数据强大"吗?谷歌搜索返回指向你的引用.只是想知道所以我可以在需要时正确引用它. (4认同)
  • 谢谢Eric.好吧,我会相信你,因为我不想说"匿名报价":O (2认同)

Ree*_*sey 42

也许有一个嵌套/继承类的用例,或者可能是get/set可能包含逻辑而不是仅仅返回属性的值

即使我不需要在getter或属性的setter上使用逻辑,我个人也会使用它.使用属性(即使是私有属性)确实可以帮助您在未来验证代码,以便以后可以根据需要将逻辑添加到getter中.

如果我觉得某个属性最终可能需要额外的逻辑,我有时会将其包装到私有属性而不是使用字段,因此我不必在以后更改我的代码.


在一个半相关的案例中(虽然与你的问题不同),我经常在公共财产上使用私人设定者:

public string Password 
{
    get; 
    private set;
}
Run Code Online (Sandbox Code Playgroud)

这为您提供了一个公共getter,但保持setter私有.

  • 私人二手<3 (7认同)

Gre*_*ech 20

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

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

然后你可以写:this.MyType到处而不是this.mytype.Value封装它在一个地方懒惰地实例化的事实.

令人遗憾的是,C#不支持将支持字段作用于属性(即在属性定义中声明它)以完全隐藏它并确保只能通过属性访问它.

  • 我经常使用相同的技术,我也希望字段可以限定为代码体.这是一个很好的功能,但优先级低. (5认同)
  • @Eric Lippert - 在`accessor-declarations`范围内的`field-declaration`已经在我的C#愿望清单上排名第一很长一段时间了.如果您可以在某些(实际)未来版本中获得设计和实现,那么我将为您烘焙蛋糕. (5认同)
  • 同意将那里的范围界定. (2认同)

Jar*_*Par 18

私有get属性的一个好用法是计算值.有几次我有私有readonly的属性,只是对我的类型中的其他字段进行计算.它不值得一个方法,而且对其他类没有兴趣,所以它是私有属性.


Luk*_*don 12

我能想到的唯一一种用法

private bool IsPasswordSet 
{ 
     get
     {
       return !String.IsNullOrEmpty(_password);
     }
}
Run Code Online (Sandbox Code Playgroud)

  • +1 对于从其他私有变量计算的有用属性类 (2认同)
  • 为什么不使用私有方法`private bool IsPasswordSet(){return!String.IsNullOrEmpty(_password); }` (2认同)

Mat*_*eer 10

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

就像您使用属性向您的消费者提供关于您的课程构成的合同一样,您也可以出于非常类似的原因向您自己提供合同.所以,是的,我确实使用私有属性.有时,私有财产可以隐藏实现细节,例如延迟加载,事实上属性实际上是多个字段和方面的集合,或者属性需要通过每次调用实际实例化(想想DateTime.Now).绝对有时候甚至在课堂后端对自己实施这一点也是有意义的.

  • +1:“您也可以出于非常相似的原因向自己出示一份合同”是有道理的 (2认同)

Mar*_*ell 8

我在序列化中使用它们,DataContractSerializer或者支持这种用法的protobuf-net(XmlSerializer不支持).如果您需要简化对象作为序列化的一部分,这将非常有用:

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


Ear*_*rlz 6

我一直做的一件事是将"全局"变量/缓存存储到 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;
  }
}
Run Code Online (Sandbox Code Playgroud)


Han*_*son 5

我时不时地使用它们.当您可以轻松地在属性中放入断点或者可以添加日志语句等时,它们可以使调试更容易.

如果您以后需要以某种方式更改数据类型或者需要使用反射,也可以使用它.


Yoh*_*hyo 5

我使用私有属性来减少访问经常使用的子属性的代码.

    private double MonitorResolution
    {
        get { return this.Computer.Accesories.Monitor.Settings.Resolution; }
    }
Run Code Online (Sandbox Code Playgroud)

如果有许多子属性,它很有用.