【问题标题】:Multithreading with Async gives a TypeCasting Error when using TaskEx.WhenAll()使用 TaskEx.WhenAll() 时,异步多线程会产生 TypeCasting 错误
【发布时间】:2012-07-15 00:12:55
【问题描述】:

在下面的代码中,我试图在另一个线程中执行一个返回值的方法。但是,它只是不起作用!!!

    public void main()
    {
       lstChapters.DataContext = await TaskEx.WhenAll(LoadChapters());
    }



   //CAN'T use  async in this function, it requires Task<> which
   //Error appears on the code inside []

   public [async Task<object>] Convert(object[] values, Type targetType,
     object parameter, System.Globalization.CultureInfo culture)
   {
      dictChapters data = await IQ_LoadQuranXML.LoadChapters(TypeIndex);
   }




    internal static async Task< IEnumerable<dictChapters>> LoadChapters()
    {
        var element = XElement.Load("xml/chapters.xml");

        Task < IEnumerable < dictChapters >>  something = (Task<IEnumerable<dictChapters>>)  await TaskEx.Run(delegate
        {

        IEnumerable<dictChapters> Chapters =  
           from var in element.Descendants("chapter")
           orderby var.Attribute("index").Value
           select new dictChapters
           {
              ChapterIndex = Convert.ToInt32(var.Attribute("index").Value),
              ChapterArabicName = var.Attribute("name").Value,
              ChapterType = var.Attribute("type").Value,
           };
            return Chapters;}
        );

        return something; //An ERROR on this line
     }

    //Overriding method which does not return IEnumerable type. And it accepts index as integer.
    internal static dictChapters LoadChapters(string chIdx = "0")
    {
        int chIdxInt = Convert.ToInt32(chIdx);
        List<dictChapters> Chapters = (List<dictChapters>)  LoadChapters(); // ERROR is on this line too
        return Chapters.ElementAt(chIdxInt - 1); //index of chapter in the element starts from 0
    }

错误是:

无法将类型“System.Threading.Tasks.Task&lt;System.Collections.Generic.IEnumerable&lt;iq_main.dictChapters&gt;&gt;”隐式转换为“System.Collections.Generic.IEnumerable&lt;iq_main.dictChapters&gt;”。存在显式转换(您是否缺少演员表?)

另一个错误是..

无法将类型“System.Threading.Tasks.Task&lt;System.Collections.Generic.List&lt;iq_main.dictChapters&gt;&gt;”转换为“System.Collections.Generic.List&lt;iq_main.dictChapters&gt;

当我像 return (IEnumerable&lt;dictChapters&gt;) something 这样明确地投射“某物”时,然后在运行时,我得到“InvalidCastException”。

【问题讨论】:

  • 有人能告诉我错误的原因吗?还有一个关于斯蒂芬回答的讨论,我不明白同步/异步的逻辑。当我按照斯蒂芬的建议更改我的代码时,我收到另一个错误,另外,用户界面停止响应并且进度条的活动不可见。

标签: c# multithreading async-await


【解决方案1】:

实际上,您会更早地收到运行时转换错误。问题是您对TaskEx.Run 结果的投射。当您 await 某事时,Task 包装器将被删除。

public void main()
{
  lstChapters.DataContext = await LoadChapters();
}

internal static Task<List<dictChapters>> LoadChapters()
{
  return TaskEx.Run(delegate
  {
    var element = XElement.Load("xml/chapters.xml");
    IEnumerable<dictChapters> Chapters =  
        from var in element.Descendants("chapter")
        orderby var.Attribute("index").Value
        select new dictChapters
        {
          ChapterIndex = Convert.ToInt32(var.Attribute("index").Value),
          ChapterArabicName = var.Attribute("name").Value,
          ChapterType = var.Attribute("type").Value,
        };
    return Chapters.ToList();
  });
}

您的代码还存在一些其他问题。请记住,像这样的枚举是延迟执行的。您可能希望return Chapters.ToList(); 以便在线程池线程上进行 XML 解析。

【讨论】:

  • 嗯,什么都没有改变。即使我返回了 chapters.ToList()... 执行 IEnumerable 代码块仍然需要很长时间。
  • 是的,它仍然抱怨TaskException
  • 加载仍然是同步的(就像在原始代码中一样)
  • @saafh:我修复了你的类型转换错误。你现在到底在问什么?
  • Stephen - 由于该方法中没有任何内容调用异步方法,并且由于它已被标记为异步,因此可能删除 Task.Run 并使用 await Task.Yield 启动该方法会更简单?
【解决方案2】:

由于您确实在 TaskEx.Run 上等待,因此您返回的是可枚举,而不是任务。

对于您正在执行的操作,我建议将 LoadChapters 保留为正常/同步代码,然后通过 Task.Run 调用它,或者按原样调用它。

由于延迟执行,AFAICT 您当前的代码实际上并没有任何帮助,因为您仍在同步执行加载。

可以删除 main 中的 Task.WhenAll,只需等待 LoadChapters(或任何异步方法

【讨论】:

  • 好的!我现在已经删除了等待并正常运行代码。但是现在,UI 卡住了仍然无响应或几秒钟,并且进度条没有显示任何活动。
猜你喜欢
  • 2017-03-10
  • 2020-10-30
  • 1970-01-01
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 2016-12-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多