ean*_*son 48 c# mef lazy-evaluation
我最近在整个应用程序中开始使用Lazy,我想知道在使用时是否有任何明显的消极方面需要考虑Lazy<T>?
我试图Lazy<T>尽可能经常使用,主要是为了帮助减少加载但非活动插件的内存占用.
Gle*_*eno 19
我将对我的评论进行一些扩展,其内容如下:
我刚开始使用Lazy,发现它通常表明设计不好; 或者程序员的懒惰.另外,一个缺点是你必须对scoped up变量保持警惕,并创建适当的闭包.
例如,我曾经用来Lazy<T>创建用户可以在我的(无会话)MVC应用程序中看到的页面.它是一个指导向导,因此用户可能希望转到随机的上一步.在进行握手时,会创建一个Lazy<Page>对象数组,如果用户指定为步骤,则会评估该确切页面.我发现它提供了良好的性能,但有些方面我不喜欢,例如我的许多foreach构造现在看起来像这样:
foreach(var something in somethings){
var somethingClosure = something;
list.Add(new Lazy<Page>(() => new Page(somethingClosure));
}
Run Code Online (Sandbox Code Playgroud)
即你必须非常积极地处理关闭问题.否则,我认为存储lambda并在需要时对其进行评估并不会造成如此糟糕的性能损失.
另一方面,这可能表明程序员是一个Lazy<Programmer>,在某种意义上你不想现在不考虑你的程序,而是在需要时让正确的逻辑进行评估,例如在我的例子中 - 而不是建立那个数组,我可以弄清楚具体请求的页面是什么; 但我选择懒惰,并采取一切措施.
编辑
对我来说,Lazy<T>在使用并发时也会有一些诡计.例如,有ThreadLocal<T>一些场景,以及针对特定多线程场景的几种标志配置.您可以在msdn上阅读更多内容.
在我看来,你应该总是有理由选择懒惰.根据使用情况,有几种替代方案,并且肯定存在这种结构合适的情况.但不要仅仅因为它很酷而使用它.
例如,我在其他一个答案中没有得到页面选择示例中的要点.使用Lazy列表来选择单个元素可以直接使用委托列表或字典来完成,而无需使用Lazy或使用简单的switch语句.
所以最明显的选择是
与此相反,懒惰通常适用于
小智 7
这不是一个消极的方面,但对于懒惰的人来说是一个骗局:).
延迟初始化器就像静态初始化器.他们跑了一次.如果抛出异常,则会缓存异常,并且对.Value的后续调用将抛出相同的异常.这是设计的,并在文档中提到... http://msdn.microsoft.com/en-us/library/dd642329.aspx:
valueFactory抛出的异常会被缓存.
因此,以下代码永远不会返回值:
bool firstTime = true;
Lazy<int> lazyInt = new Lazy<int>(() =>
{
if (firstTime)
{
firstTime = false;
throw new Exception("Always throws exception the very first time.");
}
return 21;
});
int? val = null;
while (val == null)
{
try
{
val = lazyInt.Value;
}
catch
{
}
}
Run Code Online (Sandbox Code Playgroud)
我开始使用Lazy<T>主要是因为它在从数据库加载资源时具有并发功能.因此,我摆脱了锁定对象和可论证的锁定模式.在我的情况下,ConcurrentDictionary+ Lazy作为我的一天的价值,感谢@Reed Copsey和他的博客文章
这看起来如下.而不是打电话:
Run Code Online (Sandbox Code Playgroud)MyValue value = dictionary.GetOrAdd( key, () => new MyValue(key));我们改为使用ConcurrentDictionary>,并写:
Run Code Online (Sandbox Code Playgroud)MyValue value = dictionary.GetOrAdd( key, () => new Lazy<MyValue>( () => new MyValue(key))) .Value;
Lazy<T>到目前为止没有注意到的缺点.