【问题标题】:C# check for cancellation token during for loopC# 在 for 循环期间检查取消令牌
【发布时间】:2021-01-08 03:41:15
【问题描述】:

我不完全了解取消令牌,但我相信这是我需要使用的。

我有一个包含文件路径的列表框和一个方法 (ProcesstListSort),它遍历列表框中的每个文件路径并根据文件类型执行不同的方法。 ProcessListSort 从另一个方法调用,即从按钮单击调用。我正在尝试在后台任务中运行BeginEverything,因为它锁定了 UI。在这种情况下实施取消令牌检查的最佳位置是什么?

单击此按钮将启动该过程:

public async void button1_Click(object sender, EventArgs e)
{
    Task task1 = new Task(BeginEverything);
    task1.Start();
    await task1;
}

哪个启动这个:

public void BeginEverything()
{
    CreateThing1();
    CreateThing2();
    ProcessListSort();  //This is the one I think I need to interrupt because it's the longest
    CreateThing3();
    CreateThing4();
}

在此处启动最长的任务(根据文件类型对文件进行排序并执行其他方法,将文件路径传递给其他方法):

public void ProcessListSort()
{
    for (int i = 0; i < listBox2.Items.Count; i++)
    {
        string p = listBox2.Items[i].ToString();
        FileAttributes attr = File.GetAttributes(p);

        if (p.EndsWith(".zip"))
        {
            Method1(p);
        }
        if (p.EndsWith(".txt"))
        {
            Method2(p);
        }
        if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
        {
            Method3(p);
        }
        else
        {
            Method4(p);
        }
    }
}

单击取消按钮后立即取消是理想的,但我会满足于在ProcessedListSort 中处理的每个文件之间取消。我认为问题是我正在运行其他方法的方法,我不确定是否需要应用取消检查。我得到的最接近的是它看到取消令牌的地方,但只有在一切都已经执行后才“取消”。

非常感谢任何其他建议或替代方法的链接。我知道我做错了很多事情。

【问题讨论】:

标签: c# winforms for-loop cancellation cancellation-token


【解决方案1】:

您必须创建一个CancellationTokenSource,然后将CancellationToken 传递给您要取消的方法。

private CancellationTokenSource _cts =
        new CancellationTokenSource( );

public async void OnClick( object sender, EventArgs args )
{
    // Disable your button here.

    var token = _cts.Token;
    try { await Task.Run( ( ) => LongRunning( token ), token ); }
    catch( OperationCanceledException )
    {
        Console.WriteLine( "Task was cancelled" );
    }            
    // Enable your button here.
}

public void OnCancel( object sender, EventArgs args )
{
    _cts.Cancel( );
    _cts.Dispose( );
    _cts = new CancellationTokenSource( );
}

public void LongRunning( CancellationToken token = default )
{
    // You can either check for cancellation
    // or throw if cancelled.

    // If cancellation is requested this will throw an
    // OperationCanceledException.
    token.ThrowIfCancellationRequested( );

    // If you don't want to throw you can check the
    // CancellationToken to see if cancellation was requested.
    if ( token.IsCancellationRequested )
        return;
   
    // You can also pass the token to other methods that
    // you want to observe cancellation.
    AnotherLongRunning( token );
}

【讨论】:

  • 我想我在这方面取得了进展,但是 OnCancel 上面做了什么?它似乎没有链接到任何东西。现在,我有它的工作,除了当我点击取消按钮时,它会抛出一个看似随机的错误(System.IO.IOException:'文件'C:\Test\Testing\sample.zip'已经存在。' ),但至少在按下按钮时会发生这种情况。我是否只是以某种方式捕获了该错误,而这会中断其余的进程?
  • OnCancel 是一个 Button 事件处理程序。假设用户在您的 UI 上单击开始 Button。该click 事件的事件处理程序是OnClick 方法。当点击Button 时,事件处理程序OnClick 被执行并调用LongRunning 方法。现在假设用户想要取消操作,用户将在 UI 上单击取消Button。该点击事件的处理程序是OnCancel 方法。单击取消Button 时,将调用事件处理程序OnCancel。从OnCancel 方法调用'Cancel',从而取消CancellationTokens
  • 谢谢。这清除了它。它需要更多的摆动,我不认为它和你的完全一样,但它正在工作!例如,我认为它没有按设计捕获异常,我尝试用MessageBox.Show 替换Console.WriteLine( "Task was cancelled" );,但它没有显示出来。所以有些东西不对劲,但我猜我在别处抓到了令牌?我会继续测试,但到目前为止一切都很好。再次感谢。
  • 如果你有try catch else where 并且你正在捕捉Exception,那么OperationCanceledException 将在它到达OnClick 方法中的异常处理程序之前被捕获。我建议捕获特定异常,使用多个 catch 块或使用异常过滤器:catch ( Exception ex ) when ( !( ex is OperationCanceledException ) ) { }
猜你喜欢
  • 1970-01-01
  • 2019-05-20
  • 2016-08-31
  • 2012-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
相关资源
最近更新 更多