從本地 XML 檔案反序列化“所有劇集”時,我的 Windows 表單應用程式凍結。我想通過實作異步編程來解決這個問題,但不幸的是我沒有成功實作(我是初學者,這是我第一次使用 await 和 async)。
作業(但凍結)同步執行:
public class EpisodeRepository : IEpisodeRepository<Episode>
{
SerializerForXml dataManager;
List<Episode> listOfEpisodes;
public EpisodeRepository()
{
dataManager = new SerializerForXml();
listOfEpisodes = new List<Episode>();
listOfEpisodes = GetAll();
}
public List<Episode> GetAll()
{
List<Episode> listOfEpisodesDeserialized = new List<Episode>();
try
{
listOfEpisodesDeserialized = dataManager.DeserializeEpisode());
}
catch (Exception)
{
throw new SerializerException("Episode.xml", "Error when deserialize");
}
return listOfEpisodesDeserialized;
}
}
public interface IEpisodeRepository<T> : IRepository<T> where T : class
{
List<T> GetAllFeed(string url);
}
public interface IRepository<T> where T : class
{
void Create(T entity);
void Delete(int index);
void Update(int index, T entity);
void SaveChanges();
List<T> GetAll();
int GetIndex(string name);
}
我嘗試用 async 和 await 解決它:
我將 IRepository 中的介面方法更改為Task<List<T>> GetAll();
,然后將方法更改為:
public async Task<List<Episode>> GetAll()
{
List<Episode> listOfEpisodesDeserialized = new List<Episode>();
try
{
listOfEpisodesDeserialized = await Task.Run(() => dataManager.DeserializeEpisode());
}
catch (Exception)
{
throw new SerializerException("Episode.xml", "Error when deserialize");
}
return listOfEpisodesDeserialized;
}
此代碼將無法編譯,因為該方法回傳
“System.Threading.Tasks.Task<System.Collections.Generic.List<Models.Episode>>”,當該欄位的型別為“System.Collections.Generic.List<Models.Episode>”。
此代碼還會導致其他使用GetAll().FirstOrDefault(..).
uj5u.com熱心網友回復:
您應該修復一些問題以使代碼正常作業。
首先,在您的存盤庫界面中,GetAll()像這樣更改函式的回傳型別:
public interface IRepository<T> where T : class
{
void Create(T entity);
void Delete(int index);
void Update(int index, T entity);
void SaveChanges();
Task<List<T>> GetAll(); // <= Wrapped in a "Task"
int GetIndex(string name);
}
然后找到呼叫該函式的所有位置,并await在呼叫之前放置一個。也不要忘記使這些呼叫者函式也異步,并且它們的呼叫等待。
uj5u.com熱心網友回復:
使用Lazy快速解決
public EpisodeRepository()
{
dataManager = new SerializerForXml();
listOfEpisodesLazy = new Lazy<List<Episode>>(() => GetAll());
}
private listOfEpisodes => listOfEpisodesLazy.Value;
驅逐任務中繁重處理的解決方案。但是您必須在使用listOfEpisodes變數之前添加檢查。
public EpisodeRepository()
{
dataManager = new SerializerForXml();
listOfEpisodes = null;
PopulateListOfEpisodes();
}
private async Task PopulateListOfEpisodes()
{
return await Task.Run(() => {
listOfEpisodes = GetAll();
};
}
在任何情況下,都應該避免在建構式中進行繁重的操作。
uj5u.com熱心網友回復:
由于您的代碼受 CPU 限制的性質,我建議將其Task.Run直接包裝在 WinForms 應用程式中。
public async void Button_Click(object sender, MouseEventArgs agrs)
{
try
{
List<Episode> data = await Task.Run(() => repository.GetAll());
// Update UI
}
catch (Exception e)
{
// Handle exception
}
}
有一篇很好的文章解釋了原因。
而原因就是我在一個try-catch包裹的一切都是async void這往往是容易出錯,基本上會吞噬你的例外沒有填充回UI執行緒方法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/337103.html
