Lazy<T>是否应该优先于getter中的惰性初始化?

8
从.NET 4开始,可以使用Lazy<T>来惰性地初始化对象。直觉上,也可以在公共属性的getter中执行延迟初始化,以向调用者提供相同的功能。我想知道Lazy<T>是否比后者具有任何固有优势,因此应该首选它?
个人认为,Lazy<>可以快速降低代码可读性,但也许只是看到了被滥用的情况。从好的方面来说,它确保线程安全,但有许多.NET同步构造 - 或许我错了 - 可以很容易地在getter内部实现相同的功能。
在选择最佳方法时有哪些需要注意的考虑因素?

1
请给出一个不使用Lazy<T>实现的延迟初始化的示例。这并不像你想象中那么容易。 - Ben Voigt
1
可能是Cached property vs Lazy<T>的重复问题。 - default
1
默认值:错过了那个,谢谢。这可以标记为重复。@Ben Voigt:与Patrick Hofman在他的答案中所描述的类似。此外,我恳请那些给这个问题负反面评价的人提供评论,说明如何改进这个问题(不得不说我对这个网站变得多么具有攻击性感到失望)。 - w128
2个回答

10

Lazy<> 因为包含对多线程的支持,所以在创建自己的“lazy”时需要自行构建,但是它可以很有用。

对于不需要多线程的代码,我认为这将是性能最佳且可读性最好的代码(使用null-coalescing运算符)。

return variable ?? (variable = new ClassName());
请注意,由于此代码不是线程安全的,您可能会多次调用new ClassName()
那么你应该引入锁定(locking),但这会降低可读性。如果仅出于可读性考虑,在这种情况下Lazy<>可能不那么糟糕。
此外,在使用缓存属性的情况下,Lazy<>会防止您使用后备字段。

是的,这正是我通常实现延迟加载的方法——使用null-coalescing运算符和某种类型的锁定。对我来说,它看起来并不比引入大量lambda表达式等更难读,但当然这是主观的,会因情况而异。否则,这非常合理——谢谢! - w128
2
@w128我永远不会使用“某种类型的锁”来代替使用Lazy<T>,因为Lazy<T>已经为您完成了所有这些操作。 - Matthew Watson
@w128,我明确地谈论需要提供多线程安全的情况。如果您不确定以后是否需要添加多线程支持(也许不太可能),请注意Lazy<T>可以让您轻松地在线程安全和非线程安全之间切换。 - Matthew Watson
3
明确一下,如果我不需要提供线程安全(除非我认为未来可能需要添加线程安全),我将不会使用Lazy<T>。 - Matthew Watson
@MatthewWatson 谢谢,这对我来说似乎是一个很好的指南。 - w128
显示剩余2条评论

1

如果不需要多线程,您可以使用以下安全的getter:

private Foo? _variable;

public Foo Variable => _variable ?? (_variable = DoSomeHeavyTask()).Value;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接