首页 文章

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

提问于
浏览
193

我刚刚意识到C# property construct 也可以与 private 访问修饰符一起使用:

private string Password { get; set; }

虽然这在技术上很有趣,但我无法想象何时使用它,因为 private field 甚至涉及 less ceremony

private string _password;

我无法想象什么时候我需要能够在内部 get but not setset but not get 私人领域:

private string Password { get; }

要么

private string Password { set; }

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

Does anyone use private properties in C# for any reason or is it just one of those technically-possible-yet-rarely-used-in-actual-code constructs?

附录

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

当私人字段需要延迟加载时

  • 当私有字段需要额外逻辑或计算值时

  • 因为私有字段很难调试

  • 以"present a contract to yourself"

  • 在内部转换/简化公开属性作为序列化的一部分

  • 包装要在类中使用的全局变量

14 回答

  • 5

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

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

  • 2

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

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

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

  • 12

    通常的做法是仅使用get / set方法修改成员,甚至是私有方法 . 现在,这背后的逻辑是让你知道你的get / set总是以特定的方式运行(例如,触发事件),这似乎没有意义,因为那些不会包含在属性方案中......但是旧习惯很难受 .

  • 36

    当存在与属性集或get相关的逻辑(想想延迟初始化)并且该属性在类中的一些地方使用时,它是完全有意义的 .

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

  • 5

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

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

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

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

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

  • 0

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

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

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


    在半相关案例中(虽然与您的问题不同),我经常在公共 property 上使用私人制定者:

    public string Password 
    {
        get; 
        private set;
    }
    

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

  • 2

    延迟初始化是一个可以整洁的地方,例如:

    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 到处而不是 this.mytype.Value 并封装它在一个地方懒惰地实例化的事实 .

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

  • 171

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

  • 8

    我能想到的唯一一种用法

    private bool IsPasswordSet 
    { 
         get
         {
           return !String.IsNullOrEmpty(_password);
         }
    }
    
  • 17

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

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

  • 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); }
    }
    
  • 19

    我一直做的一件事是将"global"变量/缓存存储到 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;
      }
    }
    
  • 109

    好吧,正如没有人提到的那样,你可以使用它来验证数据或锁定变量 .

    • Validation
    string _password;
    string Password
    {
        get { return _password; }
        set
        {
            // Validation logic.
            if (value.Length < 8)
            {
                throw new Exception("Password too short!");
            }
    
            _password = value;
        }
    }
    
    • Locking
    object _lock = new object();
    object _lockedReference;
    object LockedReference
    { 
        get
        {
            lock (_lock)
            {
                return _lockedReference;
            }
        }
        set
        {
            lock (_lock)
            {
                _lockedReference = value;
            }
        }
    }
    

    注意:锁定引用时,不会锁定对引用对象成员的访问 .

    延迟引用:当延迟加载时,你可能最终需要执行异步,现在有AsyncLazy . 如果您使用的是旧版本而不是Visual Studio SDK 2015,或者不使用它,您也可以使用AsyncEx's AsyncLazy .

相关问题