2014-10-09 67 views
3

假設我有一個需要異步操作初始化的成員的類(例如文件I/O或Web請求)。我只需要初始化一次,而且我不想重新初始化。僅初始化異步模式

任務和異步 - 是否等待完成此任務?

這裏是目前我在做什麼的例子:

private Task _initializeTask; 
public Task InitializeAsync() 
{ 
    return _initializeTask ?? (_initializeTask = Task.Run(
      async() => 
      { 
       // Do an action requiring await here 
       await _storageField.LoadAsync(); 
      })); 
} 

這是否做什麼我想它呢?有沒有更好的方法來做到這一點?

線程安全嗎?不是一個要求,但應該考慮。

編輯:

我認爲它呢?我相信,如果_initializeTask尚未分配,那麼它將被分配一個新任務,它將啓動並等待包含在其中的異步lambda。對該方法的任何後續調用都將等待已分配給_initializedTask的已運行(或已完成)任務。

我什麼時候需要它來構造?通常我會在使用IoC容器解析的服務上使用這種方法。可以通過引用類來構造多個相關類。然後,在使用之前,它們中的每一個都在等待InitializeAsync()。如果是多個依賴類,那麼我不想在初始化它時加倍。

工廠方法?通常不會有多個需要初始化的實例構建,因此Factory方法似乎不是一個好的解決方案。我已經對文件夾包裝類使用了類似「靜態CreateAsync()」方法的東西,但是這並不允許我將初始化的文件夾註入到構造函數中。 Async Factory方法在無法與IoC構造函數注入一起使用時不會獲得任何收益。

+0

你怎麼看它? – 2014-10-09 01:21:54

+1

您希望'Lazy '適用於延遲加載行爲。或者在類的每個實例中通用的初始化代碼的靜態構造函數。 – Aron 2014-10-09 01:27:38

+1

你想要什麼時候開始初始化?在建設? – 2014-10-09 01:29:23

回答

5

你的代碼可以工作,但它不是線程安全的,_initializeTask可以在檢查它的null並在初始化之前進行更改。這將導致兩個初始化。我會考慮使用AsyncLazy<T>,它是繼承自線程安全的Lazy<T>

然後假設LoadAsync回報Task而不是Task<T>,你的代碼變得(未經測試):

private AsyncLazy<object> initializeTask = new AsyncLazy<object>(async() => 
      { 
       // Do an action requiring await here 
       await _storageField.LoadAsync(); 
       return null; 
      }); 

public Task InitializeAsync() 
{ 
    return _initializeTask.Value; 
} 

您還可以定義AsyncLazy的'非通用版本,所以你不必返回一個值從初始化例程。

public class AsyncLazy : Lazy<Task> 
{ 
    public AsyncLazy(Func<Task> taskFactory) : 
     base(() => Task.Run(taskFactory)) { } 
} 

然後你就可以使用初始化方法來初始化它,但是需要的是方法,通過編譯器是靜態的:

private AsyncLazy _initializeTask = new AsyncLazy(LoadStorageAsync); 

private static async Task LoadStorageAsync() 
{ 
    // Do an action requiring await here 
    await _storageField.LoadAsync(); 
} 

public Task InitializeAsync() 
{ 
    return _initializeTask.Value; 
} 
+0

null-coalescing運算符[鏈接](http://msdn.microsoft.com/en-us/library/ms173224.aspx)在空檢查和賦值之間不是原子的嗎?我想這太不可思議了。 這創造了一個有潛在副作用的領域嗎?雖然它基本上是執行相同的代碼,但它現在處於一個字段中,而不是一種降低代碼清晰度的方法。 AsyncLazy確實看起來像我想要的確切的東西,有沒有辦法在方法中包含它的實例,以便它更簡潔? – 2014-10-09 17:04:13

+1

我更新了使用方法的答案,但編譯器要求該方法是靜態的。 – 2014-10-09 23:15:26

+1

您可以使用'Task.Run(taskFactory)'代替使用'StartNew()'和'Unwrap()'的方法。 – svick 2014-10-10 13:23:33

0

從常規初始化函數運行異步任務。在常規函數中,檢查您的應用程序是否已經有一個與您的期望相符的加載數據集。如果數據不存在,則調用異步函數。

... 
If (BooleanFunctionToDetermineIfDataIsNotPresent){FunctionToLoadFreshData} 
... 


Private Async Void FunctionToLoadFreshData{...} 

加載數據的函數不能返回一個值,以免它成爲一個任務本身。