如何在具有返回类型的方法中调用异步方法
本文关键字:方法 调用 异步方法 返回类型 | 更新日期: 2023-09-27 18:31:35
这是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;