9

如果是这样,为什么?什么是“长期运行”?

在属性访问器中施展魔法似乎是我作为类设计师的特权。我一直认为这就是 C# 的设计者将这些东西放在那里的原因——所以我可以做我想做的事。

当然,最好的做法是尽量减少对课程用户的意外,因此在方法中嵌入真正长时间运行的东西(例如,10 分钟的蒙特卡罗分析)是有意义的。

但是假设一个 prop 访问器需要一个 db 读取。我已经打开了数据库连接。db 访问代码在属性访问器中是否在正常预期范围内是“可接受的”?

4

8 回答 8

22

就像您提到的那样,这对课程的用户来说是一个惊喜。人们习惯于用属性来做这样的事情(人为的例子如下:)

foreach (var item in bunchOfItems)
    foreach (var slot in someCollection)
        slot.Value = item.Value;

这看起来很自然,但如果item.Value实际上每次访问时都在访问数据库,那将是一场小灾难,并且应该以与此等效的方式编写:

foreach (var item in bunchOfItems)
{
   var temp = item.Value;
   foreach (var slot in someCollection)
      slot.Value = temp;
}

请帮助引导使用您的代码的人们远离这样的隐患,并将慢的东西放在方法中,让人们知道它们很慢。

当然,也有一些例外。只要延迟加载不会花费非常长的时间,延迟加载就可以了,并且有时使事物属性对于反射和数据绑定相关的原因非常有用,所以也许你会想要打破这个规则。但是在没有特定理由的情况下,违反惯例并违反人们的期望并没有多大意义。

于 2009-05-19T15:42:45.213 回答
13

除了已经发布的好的答案之外,我还要补充一点,当您检查类的实例时,调试器会自动显示属性的值。你真的想调试你的代码并在每次检查你的类时在调试器中进行数据库获取吗?善待你代码的未来维护者,不要那样做。

此外,框架设计指南中也广泛讨论了这个问题;考虑拿起一个副本。

于 2009-05-19T18:45:02.060 回答
3

在属性访问器中读取 db 就可以了——这实际上是延迟加载的重点。我认为最重要的是将它记录好,以便类的用户了解访问该属性时可能会影响性能。

于 2009-05-19T15:40:37.130 回答
3

你可以做任何你想做的事,但你应该牢记你的 API 的使用者。访问器和修改器(getter 和 setter)应该是非常轻量级的。有了这种期望,使用您的 API 的开发人员可能会对这些属性进行频繁和闲聊的调用。如果您在实施中消耗外部资源,则可能会出现意外瓶颈。

为了一致性起见,最好坚持公共 API 的约定。如果您的实现完全是私有的,那么可能没有什么害处(除了私下与公开解决问题的不一致方法)。

于 2009-05-19T15:41:11.953 回答
3

不让属性访问器花费很长时间来执行只是一个“好习惯”。这是因为属性看起来像调用者的字段,因此调用者(即您的 API 的用户)通常假设除了“return smth;”之外什么都没有。

如果您真的需要在幕后采取一些“行动”,请考虑为此创建一种方法......

于 2009-05-19T15:41:57.443 回答
1

我看不出有什么问题,只要您提供 XML 文档,以便 Intellisense 通知对象的使用者他们正在进入什么。

我认为这是没有一个正确答案的情况之一。我的座右铭是“说总是几乎总是错误的”。您应该在任何给定情况下做最有意义的事情,而不考虑广泛的概括。

于 2009-05-19T15:40:55.150 回答
1

属性 getter 中的数据库访问很好,但尝试通过缓存值来限制访问数据库的次数。

很多时候人们在循环中使用属性而不考虑性能,所以你必须预料到这种使用。程序员在多次使用某个属性时并不总是存储它的值。

如果对这条数据可行,将从数据库返回的值缓存在私有变量中。这样访问通常非常快。

于 2009-05-19T15:50:08.083 回答
0

这与您的问题没有直接关系,但是您是否考虑过将一次加载方法与刷新参数结合使用?

class Example
    {
        private bool userNameLoaded = false;
        private string userName = "";
        public string UserName(bool refresh)
        {
            userNameLoaded = !refresh;   
            return UserName();
        }
        public string UserName()
        {
            if (!userNameLoaded)
            {
                /*
                userName=SomeDBMethod();
                */
                userNameLoaded = true;                    
            }
            return userName;         
        }
    }
于 2009-05-26T21:42:58.207 回答