我有几个可能的解决方案,但我对它们中的任何一个都不满意.第一个在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(); } } }我认为更好的设计是异步工厂,其中调用代码等待对象创建,然后接收常规对象实例.
窃听from Stephen Toub:
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.
精彩评论