我有一个需要很长时间才能初始化的对象.因此,我有能力在应用程序启动时开始初始化.对类的方法的任何后续调用我们需要有一个等待类完成初始化的延迟机制.
我有几个可能的解决方案,但我对它们中的任何一个都不满意.第一个在while循环中使用Task.Delay,第二个使用SemaphoreSlim但是涉及一些不必要的阻塞.我觉得这必须是一个相当普遍的要求,任何人都可以就如何最好地管理这个提出一些建议吗?
哦顺便说一句,这是一个Metro应用程序,所以我们有限的API
这是伪代码:
public class ExposeSomeInterestingItems { private InitialisationState _initialised; private readonly SemaphoreSlim _waiter = new SemaphoreSlim(0); public async Task Startinitialize() { if (_initialised == InitialisationState.Initialised) { throw new InvalidOperationException( "Attempted to initialise ActiveTrackDown" + "loads when it is already initialized"); } _initialised = InitialisationState.StartedInitialisation; new TaskFactory().StartNew(async () => { // This takes some time to load this._interestingItems = InterestingItemsLoader.LoadItems(); _waiter.Release(); _initialised = InitialisationState.Initialised; }); } public InterestingItem GetItem(string id) { DelayUntilLoaded(); DelayUntilLoadedAlternative(); } private async Task DelayUntilLoaded() { if (_initialised == InitialisationState.notinitialised) { throw new InvalidOperationException("Error " + "occurred attempting to access details on " + "ActiveTrackDownloads before calling initialise"); } while (true) { if (_initialised == InitialisationState.Initialised) { return; } await Task.Delay(300); } } private async Task DelayUntilLoadedAlternative() { if (_initialised == InitialisationState.notinitialised) { throw new InvalidOperationException( "Error occurred attempting to access details " + "on ActiveTrackDownloads before calling initialise"); } try { await _waiter.WaitAsync(); } finally { _waiter.Release(); } } }
解决方法
我认为更好的设计是异步工厂,其中调用代码等待对象创建,然后接收常规对象实例.
public class AsyncLazy<T> : Lazy<Task<T>> { public AsyncLazy(Func<T> valueFactory) : base(() => Task.Run(valueFactory)) { } public AsyncLazy(Func<Task<T>> taskFactory) : base(() => Task.Run(taskFactory)) { } public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); } } public static class ExposeSomeInterestingItemsFactory { public static AsyncLazy<ExposeSomeInterestingItems> Instance { get { return _instance; } } private static readonly AsyncLazy<ExposeSomeInterestingItems> _instance = new AsyncLazy<ExposeSomeInterestingItems>(() => new ExposeSomeInterestingItems()); public static void Startinitialization() { var unused = Instance.Value; } } public class ExposeSomeInterestingItems { public ExposeSomeInterestingItems() { // This takes some time to load this._interestingItems = InterestingItemsLoader.LoadItems(); } public InterestingItem GetItem(string id) { // Regular logic. No "delays". } } ... var exposeSomeInterestingItems = await ExposeSomeInterestingItemsFactory.Instance; var item = exposeSomeInterestingItems.GetItem("id");
这样,您就可以很好地遵守单一责任原则:
> AsyncLazy< T>结合任务< T>与Lazy< T> (因此仅在需要时才异步创建实例).
> ExposeSomeInterestingItemsFactory包含构造逻辑.
> ExposeSomeInterestingItems仅涉及公开有趣的项目,而不是必须使用异步延迟污染其所有成员.
此外,此解决方案始终是异步的(无阻塞),这很好(特别是对于Metro应用程序).
更新,2012-09-14:我已经使用了这段代码并将其清理干净并将其评论为on my blog.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。