【问题标题】:Infinite Loop when using foreach C#使用 foreach C# 时的无限循环
【发布时间】:2015-01-09 17:16:09
【问题描述】:

我正在使用 c# 和 Visual Studio 2010 制作一个 Word 插件。

我做了一个简单的测试代码来接受所有的文档修订如下:

if (CurrentDocument.Revisions.Count > 0)
{
    Project.LoadingWindow.LoadingWindow loadingWindow = 
                new LoadingWindow.LoadingWindow("Updating...");
    loadingWindow.ProgressBarVisibility = Visibility.Collapsed;
    System.Windows.Threading.Dispatcher loadingWindowDispatcher = 
                loadingWindow.Dispatcher;

    BackgroundWorker worker = new BackgroundWorker();
    worker.WorkerReportsProgress = false;
    worker.WorkerSupportsCancellation = false;
    worker.DoWork += delegate
    {
        List<Revision> revisions = new List<Revision>();
        int count = 0;
        foreach (Revision rev in CurrentDocument.Revisions)
        {
             count++;
             revisions.Add(rev);
        }
        AcceptRevisions(revisions, loadingWindowDispatcher, loadingWindow);

        worker.Dispose();
        worker = null;
     };

     worker.RunWorkerAsync();
     loadingWindow.Show();
}

如果我在 foreach 之后放置断点,调试将无法到达。

CurrentDocument.Revisions.Count 为 618

但是使用 int 计数器,我可以看到计数轻松达到 9000!

我做错了什么?我对 Visual Studio 和 C# 有点陌生,但我似乎无法弄清楚可能发生了什么。

【问题讨论】:

  • 很抱歉,但这是不可能的。 foreach 是确定性的。
  • 抱歉,添加了计数器。
  • @PatrickHofman:如果您枚举的集合在您枚举时被修改,那么所有的赌注都会被取消。如果是这种情况,我们无法从代码中分辨出来,但我已经看到 foreach 没有终止的循环。
  • @JeroenMostert,正在使用 foreach,这意味着将抛出 Collection was modified; enumeration operation may not execute.
  • @Patrick Hofman, @Idle_Mind:当且仅当集合实际实现了检测这一点的逻辑时才有效,即使这样,它也仅在特定情况下有效。例如,List&lt;T&gt; 将可靠地检测来自单个线程的修改,因为它维护了一个版本计数器,但如果您从多个线程修改同一个实例,这不一定有效。

标签: c# visual-studio-2010 foreach ms-word add-in


【解决方案1】:

我在这里是一个完整的 Word Interop NOOB。 必须下载并安装 VS 的 Office 模板,这样我才能玩这个。我也不使用 WPF,所以我用一个 BackgroundWorker 和一个标签替换了一个普通的 WinForms 表单。

您为什么不直接与Application.ActiveDocument.Revisions 合作?

我在我的 Word 文档中添加了一个按钮并填充了一个列表,然后将其传递给了一个表单:

    private void button1_Click(object sender, EventArgs e)
    {
        if (Application.ActiveDocument.Revisions.Count > 0)
        {
            List<Revision> revisions = new List<Revision>();
            foreach (Revision rev in Application.ActiveDocument.Revisions)
            {
                revisions.Add(rev);
            }

            frmAcceptRevisions accept = new frmAcceptRevisions(revisions);
            accept.ShowDialog();
        }
    }

这里是 frmAcceptRevisions:

public partial class frmAcceptRevisions : Form
{

    private List<Revision> _Revisions = null;

    public frmAcceptRevisions(List<Revision> Revisions)
    {
        InitializeComponent();
        this._Revisions = Revisions;
        this.Shown += frmAcceptRevisions_Shown;
    }

    private void frmAcceptRevisions_Shown(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        for(int i = 0; i < _Revisions.Count; i++)
        {
            backgroundWorker1.ReportProgress(i + 1);
            _Revisions[i].Accept();
            System.Threading.Thread.Sleep(1000); // for illustrative purposes only
        }
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        label1.Text = "Applying Revision " + e.ProgressPercentage.ToString() + " of " + _Revisions.Count.ToString();
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("Revisions Accepted: " + _Revisions.Count.ToString());
        this.DialogResult = System.Windows.Forms.DialogResult.OK;
    }

}

然后我运行了这个项目,在我的文档中输入了一些文本,打开了跟踪更改,并进行了一些修改。当我单击按钮时,我的表单弹出,我可以看到文档中的每个修订都被接受和更改,我的表单按预期更新进度(因为我在循环中硬编码的长时间延迟)。

【讨论】:

  • 出于好奇,这里哪一部分有帮助? Application.ActiveDocument.Revisions 位或表单部分?...或两者兼而有之?
  • 实际上,这是使用“for i”而不是 foreach 的想法。因为这很奇怪。
猜你喜欢
  • 2013-07-27
  • 2023-02-25
  • 2017-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-13
  • 1970-01-01
相关资源
最近更新 更多