是不是我不应该在物业存取器中做“长期运行”的事情?

时间:2021-10-05 13:56:38

And if so, why? and what constitutes "long running"?

如果是这样,为什么?什么构成“长跑”?

Doing magic in a property accessor seems like my prerogative as a class designer. I always thought that is why the designers of C# put those things in there - so I could do what I want.

在属性访问器中做魔术似乎是我作为类设计师的特权。我一直认为这就是为什么C#的设计师把那些东西放在那里 - 所以我可以做我想要的。

Of course it's good practice to minimize surprises for users of a class, and so embedding truly long running things - eg, a 10-minute monte carlo analysis - in a method makes sense.

当然,最好的做法是尽量减少类中用户的意外,因此在一种方法中嵌入真正长时间运行的东西 - 例如,10分钟的蒙特卡罗分析 - 是有道理的。

But suppose a prop accessor requires a db read. I already have the db connection open. Would db access code be "acceptable", within the normal expectations, in a property accessor?

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

8 个解决方案

#1


Like you mentioned, it's a surprise for the user of the class. People are used to being able to do things like this with properties (contrived example follows:)

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

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

This looks very natural, but if item.Value actually is hitting the database every time you access it, it would be a minor disaster, and should be written in a fashion equivalent to this:

这看起来非常自然,但是如果每次访问时item.Value实际上都在访问数据库,那么这将是一个小小的灾难,应该以与此相当的方式编写:

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

Please help steer people using your code away from hidden dangers like this, and put slow things in methods so people know that they're slow.

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

There are some exceptions, of course. Lazy-loading is fine as long as the lazy load isn't going to take some insanely long amount of time, and sometimes making things properties is really useful for reflection- and data-binding-related reasons, so maybe you'll want to bend this rule. But there's not much sense in violating the convention and violating people's expectations without some specific reason for doing so.

当然,也有一些例外。懒惰加载是好的,只要延迟加载不会花费一些疯狂的长时间,并且有时使得属性对于反射和数据绑定相关的原因非常有用,所以也许你想要弯曲这个规则。但是,如果没有特定的理由,违反公约并违反人们的期望就没有多大意义。

#2


In addition to the good answers already posted, I'll add that the debugger automatically displays the values of properties when you inspect an instance of a class. Do you really want to be debugging your code and have database fetches happening in the debugger every time you inspect your class? Be nice to the future maintainers of your code and don't do that.

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

Also, this question is extensively discussed in the Framework Design Guidelines; consider picking up a copy.

此外,“框架设计指南”对此问题进行了广泛讨论;考虑拿一份。

#3


A db read in a property accessor would be fine - thats actually the whole point of lazy-loading. I think the most important thing would be to document it well so that users of the class understand that there might be a performance hit when accessing that property.

在属性访问器中读取db也没关系 - 这实际上是延迟加载的全部要点。我认为最重要的是将其记录得很好,以便班级用户了解访问该属性时可能会遇到性能损失。

#4


You can do whatever you want, but you should keep the consumers of your API in mind. Accessors and mutators (getters and setters) are expected to be very light weight. With that expectation, developers consuming your API might make frequent and chatty calls to these properties. If you are consuming external resources in your implementation, there might be an unexpected bottleneck.

你可以做任何你想做的事,但你应该记住你的API的消费者。配件和变换器(吸气剂和固定剂)预计重量非常轻。有了这种期望,开发人员使用您的API可能会对这些属性进行频繁且繁琐的调用。如果您在实现中消耗外部资源,则可能存在意外的瓶颈。

For consistency sake, it's good to stick with convention for public APIs. If your implementations will be exclusively private, then there's probably no harm (other than an inconsistent approach to solving problems privately versus publicly).

为了保持一致,最好坚持使用公共API的约定。如果您的实施将完全是私有的,那么可能没有任何损害(除了私下与公开解决问题的不一致方法)。

#5


It is just a "good practice" not to make property accessors taking long time to execute. That's because properties looks like fields for the caller and hence caller (a user of your API that is) usually assumes there is nothing more than just a "return smth;"

只是一个“好的做法”,不要让属性访问者花费很长时间来执行。那是因为属性看起来像调用者的字段,因此调用者(你的API的用户)通常认为只有“返回smth”;

If you really need some "action" behind the scenes, consider creating a method for that...

如果你真的需要幕后的“动作”,可以考虑为它创建一个方法......

#6


I don't see what the problem is with that, as long as you provide XML documentation so that the Intellisense notifies the object's consumer of what they're getting themselves into.

我没有看到问题是什么,只要你提供XML文档,以便Intellisense通知对象的消费者他们自己进入了什么。

I think this is one of those situations where there is no one right answer. My motto is "Saying always is almost always wrong." You should do what makes the most sense in any given situation without regard to broad generalizations.

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

#7


A database access in a property getter is fine, but try to limit the amount of times the database is hit through caching the value.

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

There are many times that people use properties in loops without thinking about the performance, so you have to anticipate this use. Programmers don't always store the value of a property when they are going to use it many times.

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

Cache the value returned from the database in a private variable, if it is feasible for this piece of data. This way the accesses are usually very quick.

如果对于这段数据可行,则将私有变量中从数据库返回的值缓存。通过这种方式访问​​通常非常快。

#8


This isn't directly related to your question, but have you considered going with a load once approach in combination with a refresh parameter?

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

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;         
        }
    }

#1


Like you mentioned, it's a surprise for the user of the class. People are used to being able to do things like this with properties (contrived example follows:)

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

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

This looks very natural, but if item.Value actually is hitting the database every time you access it, it would be a minor disaster, and should be written in a fashion equivalent to this:

这看起来非常自然,但是如果每次访问时item.Value实际上都在访问数据库,那么这将是一个小小的灾难,应该以与此相当的方式编写:

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

Please help steer people using your code away from hidden dangers like this, and put slow things in methods so people know that they're slow.

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

There are some exceptions, of course. Lazy-loading is fine as long as the lazy load isn't going to take some insanely long amount of time, and sometimes making things properties is really useful for reflection- and data-binding-related reasons, so maybe you'll want to bend this rule. But there's not much sense in violating the convention and violating people's expectations without some specific reason for doing so.

当然,也有一些例外。懒惰加载是好的,只要延迟加载不会花费一些疯狂的长时间,并且有时使得属性对于反射和数据绑定相关的原因非常有用,所以也许你想要弯曲这个规则。但是,如果没有特定的理由,违反公约并违反人们的期望就没有多大意义。

#2


In addition to the good answers already posted, I'll add that the debugger automatically displays the values of properties when you inspect an instance of a class. Do you really want to be debugging your code and have database fetches happening in the debugger every time you inspect your class? Be nice to the future maintainers of your code and don't do that.

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

Also, this question is extensively discussed in the Framework Design Guidelines; consider picking up a copy.

此外,“框架设计指南”对此问题进行了广泛讨论;考虑拿一份。

#3


A db read in a property accessor would be fine - thats actually the whole point of lazy-loading. I think the most important thing would be to document it well so that users of the class understand that there might be a performance hit when accessing that property.

在属性访问器中读取db也没关系 - 这实际上是延迟加载的全部要点。我认为最重要的是将其记录得很好,以便班级用户了解访问该属性时可能会遇到性能损失。

#4


You can do whatever you want, but you should keep the consumers of your API in mind. Accessors and mutators (getters and setters) are expected to be very light weight. With that expectation, developers consuming your API might make frequent and chatty calls to these properties. If you are consuming external resources in your implementation, there might be an unexpected bottleneck.

你可以做任何你想做的事,但你应该记住你的API的消费者。配件和变换器(吸气剂和固定剂)预计重量非常轻。有了这种期望,开发人员使用您的API可能会对这些属性进行频繁且繁琐的调用。如果您在实现中消耗外部资源,则可能存在意外的瓶颈。

For consistency sake, it's good to stick with convention for public APIs. If your implementations will be exclusively private, then there's probably no harm (other than an inconsistent approach to solving problems privately versus publicly).

为了保持一致,最好坚持使用公共API的约定。如果您的实施将完全是私有的,那么可能没有任何损害(除了私下与公开解决问题的不一致方法)。

#5


It is just a "good practice" not to make property accessors taking long time to execute. That's because properties looks like fields for the caller and hence caller (a user of your API that is) usually assumes there is nothing more than just a "return smth;"

只是一个“好的做法”,不要让属性访问者花费很长时间来执行。那是因为属性看起来像调用者的字段,因此调用者(你的API的用户)通常认为只有“返回smth”;

If you really need some "action" behind the scenes, consider creating a method for that...

如果你真的需要幕后的“动作”,可以考虑为它创建一个方法......

#6


I don't see what the problem is with that, as long as you provide XML documentation so that the Intellisense notifies the object's consumer of what they're getting themselves into.

我没有看到问题是什么,只要你提供XML文档,以便Intellisense通知对象的消费者他们自己进入了什么。

I think this is one of those situations where there is no one right answer. My motto is "Saying always is almost always wrong." You should do what makes the most sense in any given situation without regard to broad generalizations.

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

#7


A database access in a property getter is fine, but try to limit the amount of times the database is hit through caching the value.

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

There are many times that people use properties in loops without thinking about the performance, so you have to anticipate this use. Programmers don't always store the value of a property when they are going to use it many times.

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

Cache the value returned from the database in a private variable, if it is feasible for this piece of data. This way the accesses are usually very quick.

如果对于这段数据可行,则将私有变量中从数据库返回的值缓存。通过这种方式访问​​通常非常快。

#8


This isn't directly related to your question, but have you considered going with a load once approach in combination with a refresh parameter?

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

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;         
        }
    }