[英]How to call async method inside a method which has return type?
這是Windows Phone 8.1 Silverlight應用程序。 我有一個文件關聯。 為此,我有一堂課
class AssociationUriMapper : UriMapperBase
{
public override Uri MapUri(Uri uri)
{
//here I'm getting file ID etc..
}
// here I want to read the file content & determine the file type because,
// the case is, even same file extension can contain different type of data
switch (fileType)
{
//here I'm calling appropriate page according to type
}
}
現在的問題是MapUri被重寫方法,因此它必須具有返回類型。 而OpenStreamForReadAsync()是一個異步方法。 我嘗試了Wait()方法,創建新任務,然后在其中調用Start(),Wait(),但沒有成功。 目前我的代碼是
class AssociationUriMapper : UriMapperBase
{
string strData = "";
public override Uri MapUri(Uri uri)
{
strUri = uri.ToString();
// File association launch
if (strUri.Contains("/FileTypeAssociation"))
{
// Get the file ID (after "fileToken=").
int nFileIDIndex = strUri.IndexOf("fileToken=") + 10;
string strFileID = strUri.Substring(nFileIDIndex);
string strFileName = SharedStorageAccessManager.GetSharedFileName(strFileID);
string strIncomingFileType = Path.GetExtension(strFileName);
fnCopyToLocalFolderAndReadContents(strFileID);
switch (fileType)
{
case ".gmm":
//determine if gmm is text
if (objGMM.fnGetGMMType() == GMMFILETYPE.TXT)
{
return new Uri("/PageReadText.xaml?data=" + strData, UriKind.Relative);
}
break;
}
}
}
async void fnCopyToLocalFolderAndReadContents(string strIncomingFileId)
{
StorageFolder objLocalFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
objFile = await SharedStorageAccessManager.CopySharedFileAsync(objLocalFolder, TEMP.gmm, NameCollisionOption.ReplaceExisting, strIncomingFileId);
using (StreamReader streamReader = new StreamReader(objFile))
{
strData = streamReader.ReadToEnd();
}
}
}
我要做的第一件事就是改變邏輯。 當操作系統詢問您的應用程序是否支持Uri映射時,它會立即得到答復。 它不希望該應用程序復制和讀取文件。 通常,Uri映射非常恆定。 一個應用程序總是支持一個,或者不支持。
因此,我要做的第一件事是在啟動時加載所有映射文件, 然后使用所有結果創建AssociationUriMapper
。 如果這不可能,那么幾乎可以肯定的是,您將Uri映射用於錯誤的事情。 它們不應該是動態的,操作系統很有可能會認為它們不是動態的。
就是說,如果您想使其正常運行,我認為最干凈的解決方案是將異步文件操作推送到另一個線程,然后在該線程上進行阻塞:
public override Uri MapUri(Uri uri)
{
strUri = uri.ToString();
// File association launch
if (strUri.Contains("/FileTypeAssociation"))
{
// Get the file ID (after "fileToken=").
int nFileIDIndex = strUri.IndexOf("fileToken=") + 10;
string strFileID = strUri.Substring(nFileIDIndex);
string strFileName = SharedStorageAccessManager.GetSharedFileName(strFileID);
string strIncomingFileType = Path.GetExtension(strFileName);
var strData = Task.Run(() => CopyToLocalFolderAndReadContents(strFileID)).GetAwaiter().GetResult();
switch (fileType)
{
case ".gmm":
//determine if gmm is text
if (objGMM.fnGetGMMType() == GMMFILETYPE.TXT)
{
return new Uri("/PageReadText.xaml?data=" + strData, UriKind.Relative);
}
break;
}
}
}
async Task<string> CopyToLocalFolderAndReadContentsAsync(string strIncomingFileId)
{
StorageFolder objLocalFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
objFile = await SharedStorageAccessManager.CopySharedFileAsync(objLocalFolder, TEMP.gmm, NameCollisionOption.ReplaceExisting, strIncomingFileId);
using (StreamReader streamReader = new StreamReader(objFile))
{
return streamReader.ReadToEnd();
}
}
我不太喜歡它,因為它涉及同步調用異步方法的代碼。 但是以下應該起作用:
class AssociationUriMapper : UriMapperBase
{
public override Uri MapUri(Uri uri)
{
strUri = uri.ToString();
// File association launch
if (strUri.Contains("/FileTypeAssociation"))
{
// Get the file ID (after "fileToken=").
int nFileIDIndex = strUri.IndexOf("fileToken=") + 10;
string strFileID = strUri.Substring(nFileIDIndex);
string strFileName = SharedStorageAccessManager.GetSharedFileName(strFileID);
string strIncomingFileType = Path.GetExtension(strFileName);
string strData = fnCopyToLocalFolderAndReadContents(strFileID).Result;
switch (fileType)
{
case ".gmm":
//determine if gmm is text
if (objGMM.fnGetGMMType() == GMMFILETYPE.TXT)
{
return new Uri("/PageReadText.xaml?data=" + strData, UriKind.Relative);
}
break;
}
}
}
async Task<string> fnCopyToLocalFolderAndReadContents(string strIncomingFileId)
{
StorageFolder objLocalFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
objFile = await SharedStorageAccessManager.CopySharedFileAsync(objLocalFolder, TEMP.gmm, NameCollisionOption.ReplaceExisting, strIncomingFileId).ConfigureAwait(false);
using (StreamReader streamReader = new StreamReader(objFile))
{
return streamReader.ReadToEnd();
}
}
}
對我來說,一個更大的問題是,為什么要實現一個像MapUri()
這樣的方法,使得它需要調用異步方法,並涉及這種可能耗時的I / O。 我的意思是,也許實際上這是必需的,但這似乎有些偏離。 不幸的是,這個問題沒有足夠的上下文讓我覺得我可以提供其他選擇。
不幸的是,沒有覆蓋非異步方法的“漂亮方法”。
您能做的最好的事情就是確保將ConfigureAwait(false)
添加到異步調用中,以確保SynchronizationContext
不流動和死鎖,然后訪問返回的Task
的Result
屬性。
我要做的是更改讀取文件的方法以返回Task<string>
:
async Task<string> CopyToLocalFolderAndReadContents(string strIncomingFileId)
{
StorageFolder objLocalFolder = Windows.Storage.ApplicationData.Current
.LocalFolder;
objFile = await SharedStorageAccessManager
.CopySharedFileAsync(objLocalFolder, TEMP.gmm,
NameCollisionOption.ReplaceExisting,
strIncomingFileId)
.AsTask().ConfigureAwait(false);
using (StreamReader streamReader = new StreamReader
(await objFile.OpenStreamForReadAsync().ConfigureAwait(false)))
{
return await streamReader.ReadToEndAsync().ConfigureAwait(false);
}
}
然后將呼叫站點更改為:
string data = CopyToLocalFolderAndReadContents(strFileID).Result;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.