【问题标题】:What is the best practice for using .NET Properties?使用 .NET 属性的最佳做法是什么?
【发布时间】:2010-02-25 15:04:29
【问题描述】:

我有点困惑我应该对属性做多少。 我听说属性应该始终代表类的逻辑属性。 Get 和 Set 几乎从不抛出 ArgumentOutOfRange 异常。真的吗?下面的例子完全错误吗?

public bool DeviceRegistered
{
    get{ return _Registered;}
    set
    {
        if(value)
        {
            RegisterDevice();
            _Registered = true;
        }
        else
        {
            UnRegisterDevice();
            _Registered = false;
        }
    }
}

另外,如果同一个类中的一个方法想要改变一个属性的值,是应该通过属性的set访问器还是直接修改私有变量_Registered?

如果您在使用属性时有任何其他建议,请包括! 谢谢

【问题讨论】:

    标签: .net properties exception


    【解决方案1】:

    这是来自 MSDN 的 Design Guidelines for properties 的链接。请特别注意Property vs Method 部分。

    根据我个人的经验,您不应该使用属性来做很多工作。他们应该返回已经检索到的信息。我目前正在开发一个代码库,该代码库具有许多从 Web 服务检索信息的延迟加载属性。在调试时查看类的属性会导致评估所有属性,从而导致功能评估超时和 ASP.NET 进程崩溃。

    【讨论】:

    • 你会建议对延迟加载的属性做什么?
    • 我们决定使用服务来填充属性。大多数时候,我们发现该对象在每个请求中只使用一次。如果多次使用,服务会将其存储在缓存中(例如 Http.Items)。这种缓存检索逻辑也可以被抽象出来,并根据需要在服务之间共享。
    • @Greg:将私有支持字段设为System.Lazy<T>return _lazyValue.Value; 来自属性,并将属性标记为[DebuggerBrowsable(DebuggerBrowsableState.Never)]
    • @John Saunders:您可以在 MEF 源代码分发中的 MS-PL 下获取它(链接 1),或者您可以使用 Reactive Extensions for .NET 中更好的 System.Threading.dll (链接 2)。 1)mef.codeplex.com 2)msdn.microsoft.com/en-us/devlabs/ee794896.aspx
    【解决方案2】:

    在这种情况下,我认为使用方法更合乎逻辑,因为您正在执行一项操作。

    private volatile bool _DeviceRegistered;
    private readonly object _Lock = new object();
    
    public bool DeviceRegistered
    {
        get { return _DeviceRegistered; }
    }
    
    public void RegisterDevice()
    {
        lock (_Lock) // A good idea to lock
        {
            // ........
            _DeviceRegistered = true;
        }
    }
    
    public void UnregisterDevice()
    {
        lock (_Lock)
        {
            // ........
            _DeviceRegistered = false;
        }
    }
    

    【讨论】:

    • 您可能还想锁定您的 get 属性访问器,以便在属性为阅读。
    • @Jesse - 问题是我们是否想在注册设备时占用其他线程?我认为为了安全起见你是对的,但这真的取决于我们没见过的代码。
    【解决方案3】:

    一个狭窄的答案:我喜欢使用只读属性,当我有一个需要一些工作才能获取的值,但我想要“世界其他地方”(甚至同一个类中的调用者)将其视为一个变量,其值总是可用的。该属性将完成获取值的工作,然后简单地返回(可能通过缓存/等优化)。

    另一种选择是“get”方法,这很好......但我喜欢使用属性,因为我不希望调用者背负着获取/计算值涉及工作的想法。

    【讨论】:

      【解决方案4】:

      在这种情况下,由于您在属性更改时调用另一个方法,如果您想保留该功能,请使用Accessor 设置它。如果它只是存储一个值,那么直接使用 _Registered 变量会稍微好一些。

      【讨论】:

        【解决方案5】:

        我承认,让一个属性做的不仅仅是持有一个价值通常是有意义的,但在我看来,你的例子很糟糕。我会有一个注册/注销设备的方法和一个简单的获取当前状态的方法。我的一般规则是,如果我正在执行一个动作,我使用一个方法,但如果我只是更改一个值,那么一个属性更合适。现在,属性如何处理可能涉及执行一些计算或 I/O,但重要的是类消费者的期望。

        public void Register()
        {
          ...do some stuff...
          this.Registered = true;
        }
        
        public void Unregister()
        {
          ...do some stuff...
          this.Registered = false;
        }
        
        public bool Registered { get; private set; }
        

        另外,我甚至倾向于强制类代码通过属性——这隔离了我可能对属性如何对属性代码本身进行的任何更改。同一类的其他部分不需要知道该属性是如何工作的。显然会有例外——比如当你想要或需要避免属性执行的某些计算,但仍需要更新值时——但这是我的一般规则。

        【讨论】:

          【解决方案6】:

          为了解决直接使用字段或属性访问器/修改器的问题,我赞成使用属性。如果您应该在访问器中返回默认值或在 mutator 中引发属性更改事件(或类似事件),您将通过直接访问该字段来绕过此功能。如果扩展类覆盖了该属性,如果您直接访问该字段,则可能会无意中绕过扩展类。

          在某些情况下,字段访问(私有)是可行的方法,但我总是偏爱该属性,除非有充分的理由访问该字段。

          【讨论】:

            【解决方案7】:

            以下是我随着时间的推移而意识到的一些规则。大多数是我的意见,但我喜欢认为它们是好主意。 :) 编辑:我刚刚意识到Property Usage 指南中涵盖了大部分内容。

            吸气剂

            • 您应该更喜欢 getter 不改变状态。如果你有一个确实改变程序状态的getter,用[DebuggerBrowsable(DebuggerBrowsableState.Never)]标记它。
            • 希望 getter 可以从任何线程调用。
            • 更喜欢 getter 被简单地计算,因为它们的使用方式会让人们相信它们不会导致性能损失。如果它们可能需要一些时间来执行,请使用上面的 DebuggerBrowsable 属性或 [DebuggerDisplay("Some display text")] (文本被简单计算)标记它们。忘记后者可能会对调试器性能产生不利影响。
            • Getter 至少可以抛出以下异常:
              • InvalidOperationException
              • ObjectDisposedException

            二传手

            • 希望无论何时你背靠背设置两个属性,哪个先出现并不重要。
            • 如果 setter 具有无法通过公开属性进行测试的先决条件,则应将其标记为受保护或私有。
            • 可以将调用 setter 限制在特定线程,但如果您这样做,则需要对其进行记录,并且您的对象应实现 ISynchronizeInvoke 或公开 Dispatcher 属性。
            • Setter 至少可以抛出以下异常:
              • ArgumentExceptionArgumentNullExceptionArgumentOutOfRangeException 等视情况而定)
              • InvalidOperationException
              • ObjectDisposedException

            【讨论】:

              猜你喜欢
              • 2016-05-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-03-30
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多