【发布时间】:2018-11-12 23:36:09
【问题描述】:
当我想使用Lazy<T>并需要参考this时,我需要写很多样板代码:
// the private member
private Lazy<SubEventCollection> _SubEvents;
public Event()
{
// needs to be initialized in the constructor because I refer to this
_SubEvents = new Lazy<SubEventCollection3>(CreateSubEvents);
}
// the "core" body
private SubEventCollection CreateSubEvents()
{
SubEventCollection3 collection;
using ( var stream = new MemoryStream(DbSubEventsBucket) )
collection = Serializer.Deserialize<SubEventCollection3>(stream);
collection.Initialize(this);
return collection;
}
// The final property
public SubEventCollection SubEvents => _SubEvents.Value;
这一切真的有必要吗?感觉就像太多的样板和所有的地方。有没有什么捷径读起来更好看,周围没有那么多单独的样板? 我可能可以将主体移到构造函数中,但我也不喜欢这样 - 即您将 很多 重要逻辑移到构造函数中。
我的首选方式是类似于 Knockout.js / TypeScript。
subEvents = ko.lazyComputed(() =>
{
SubEventCollection3 sub_events;
using ( var stream = new MemoryStream(DbSubEventsBucket) )
sub_events = Serializer.Deserialize<SubEventCollection3>(stream);
sub_events.Initialize(this);
return sub_events;
})
这里没有很多“活动部件”,而且非常简洁。 还有哪些其他选择?我注意到我经常退回到手动的“懒惰”构造。
private SubEventCollection _SubEvents;
public SubEventCollection SubEvents
{
get
{
if ( _SubEvents == null )
{
using ( var stream = new MemoryStream(DbSubEventsBucket) )
collection = Serializer.Deserialize<SubEventCollection3>(stream);
collection.Initialize(this);
_SubEvents = collection;
}
return _SubEvents;
}
}
至少这比 Lazy 方式具有更少的“移动部分”,并且我可以将所有内容放在一起(不必将一半的逻辑放在构造函数中)。当然这还有很多其他的缺点,比如它不是线程安全的。
我是否仍然缺少其他选择?
附言 我假设有两种不同的答案 - 一种用于真正的线程安全延迟加载,另一种用于简洁版本,您不在乎它是否会意外被调用两次。
【问题讨论】:
-
lazyComputed与 C# 中的Lazy不同。例如,Lazy最多运行一次(与lazyComputed不同,它会在依赖关系发生变化时重新运行)。 -
我觉得这需要一些固执己见的回应。我经常使用
manual惰性构造的相同方法。我认为这取决于情况:stackoverflow.com/questions/6847721/when-should-i-use-lazyt -
我认为您不会比原始代码更简洁。
-
“这一切真的有必要吗?感觉样板文件太多,到处都是”听起来像是代码强迫症和语法嫉妒的案例。如果你想使用 Lazy
你会被这个模式困住。此外,Knockout.js / TypeScript 是完全不同的野兽,它们可以做这些恶作剧是有根本原因的,而 CLR 在 .Net 中不允许这样做 -
为了记录,我个人会使用
LazyWithNoExceptionCaching而不是Lazy- 但这不利于您的简洁。 stackoverflow.com/a/42567351/34092
标签: c# syntax lazy-loading boilerplate