为什么会出现“索引超出范围异常”错误?

4
在Form1的构造函数中,我有以下代码:
if (System.IO.File.Exists(keywords_path_file))
            {
                ListBoxLoadKeys(LocalyKeyWords, keywords_path_file);
            }
            else
            {
                fileExist = new StreamWriter(keywords_path_file);
                fileExist.Close();
                ListBoxLoadKeys(LocalyKeyWords, keywords_path_file);
            }

我使用断点并查看文件是否存在:
C:\Users\bout0_000\AppData\Local\GatherLinks\GatherLinks\Keywords\Keywords.txt

文件内容如下:
http://www.walla.co.il,walla
http://www.cnet.com,cnet
http://rotter.net/forum/scoops1/29961.shtml,rotter
http://vanessawest.tripod.com/crimescenephotos.html,VanessaWest
http://rotter.net/forum/scoops1/45227.shtml,scoops
https://www.google.com/search?q=live+cameras,live camera
https://www.google.com/search?q=rape+images&oq=+images&aqs=chrome..69i57.1661j0&sourceid=chrome&ie=UTF-8,hi
https://www.google.com/search?q=+images&um=1&ie=UTF-8&hl=en&tbm=isch&source=og&sa=N&tab=wi&ei=GqotUv2kA4OftAae94DoAg&biw=951&bih=457&sei=oaotUtDqM8WbtAag3IFg#hl=en&q=+and+&tbm=isch&um=1,chud
http://www.test.com,test

文件包含9个键和关键词。左边是键,右边是关键词。
然后进入这个方法:
private void ListBoxLoadKeys(Dictionary<string, List<string>> dictionary, string FileName)
        {
            List<string> urls = new List<string>();
            using (StreamReader sr = new StreamReader(FileName))
            {
                while ((line = sr.ReadLine()) != null)
                {
                    int i = line.Count();
                    tokens = line.Split(',');
                    dictionary.Add(tokens[0], tokens.Skip(1).ToList());
                    data.Add("Url: " + tokens[0] + " --- " + "Localy KeyWord: " + tokens[1]);
                    urls.Add(tokens[0]);
                }
            }
            listBox1.DataSource = data;
            listBox1.Tag = urls;
        }

在执行到这一行代码:listBox1.DataSource = data; 时,它会跳转并执行以下事件:
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {

            if (listBox1.SelectedItem != null)
            {
                label4.Text = listBox1.SelectedItem.ToString();
                string startTag = "Url: ";
                string endTag = " ---";
                int startTagWidth = startTag.Length;
                int endTagWidth = endTag.Length;
                int index = 0;
                index = label4.Text.IndexOf(startTag, index);
                int start = index + startTagWidth;
                index = label4.Text.IndexOf(endTag, start + 1);
                string g = label4.Text.Substring(start, index - start);
                label4.Text = g;
                mainUrl = g;
            }
        }

最终,我看到data和listBox1.DataSource都包含9个项目。
经过这一切,程序正在运行。 我在listBox的右侧看到了项目、键和关键字。 当我单击listBox1中的一个键时,就会在该行引发异常。
if (listBox1.SelectedItem != null)

在listBox1_SelectedIndexChanged事件中。

异常信息如下:

索引超出了数组边界

System.IndexOutOfRangeException was unhandled
  HResult=-2146233080
  Message=Index was outside the bounds of the array.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.ListBox.ItemArray.GetItem(Int32 virtualIndex, Int32 stateMask)
       at System.Windows.Forms.ListBox.get_SelectedItem()
       at GatherLinks.Form1.listBox1_SelectedIndexChanged(Object sender, EventArgs e) in d:\C-Sharp\GatherLinks\GatherLinks-2\GatherLinks\GatherLinks\Form1.cs:line 543
       at System.Windows.Forms.ListBox.OnSelectedIndexChanged(EventArgs e)
       at System.Windows.Forms.ListBox.WmReflectCommand(Message& m)
       at System.Windows.Forms.ListBox.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m)
       at System.Windows.Forms.Control.WmCommand(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.ContainerControl.WndProc(Message& m)
       at System.Windows.Forms.Form.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
       at System.Windows.Forms.Control.DefWndProc(Message& m)
       at System.Windows.Forms.Control.WmKillFocus(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ListBox.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
  InnerException: 

我知道异常的含义,但我为什么会遇到它,该如何解决?
例如,当我使用箭头向上和向下键在listBox中移动并点击其中一个键时,不会出现任何异常。但是,当我运行程序并立即使用鼠标单击listBox中的一个键时,就会出现异常。
在它们之间移动然后单击其中一个是可以的,但是首先单击其中一个会引发异常。
编辑**
我现在看到,在进入listBox1_SelectedIndexChanged事件之前,会出现此事件istBox1鼠标按下:
private void listBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (Control.ModifierKeys == Keys.Control || ( Control.ModifierKeys == Keys.Control || e.Button == MouseButtons.Left))
            {
                listBox1.SelectionMode = SelectionMode.MultiExtended;
            }
            else if (e.Button == MouseButtons.Left)
            {
                listBox1.SelectionMode = SelectionMode.One;
            }
        }

执行此行:

listBox1.SelectionMode = SelectionMode.MultiExtended;

然后回到SelectedIndexChanged事件,并在以下代码行上抛出异常:

if (listBox1.SelectedItem != null)

这也是第543行。


在调试模式下,处理此异常的代码行是什么? - provençal le breton
不确定,但是 label4.Text.Substring(start, index - start); 这段代码有点可疑。 - Alessandro D'Andria
第543行是什么?我不知道哪个方法会抛出“IndexOutOfRangeException”异常,但在您的代码中它发生在“lisbox1_SelectedIndexChanged”内部,只需在那里设置断点并逐步检查出错原因即可。 - Sinatr
看起来你正在使用 ListBox 控件进行多线程操作。是这样吗? - Sriram Sakthivel
我更新了我的问题,现在我看到它首先执行listBox的mousedown事件,然后返回到selectedindexchanged事件,最后抛出异常。 - user2760148
顺便说一句,在Form构造函数中绝对不要做这种事情。在Form_Load中完成(添加处理程序)。如果你开始在构造函数中基于你已经混乱的项目进行数据绑定,你最终会陷入困境。此外,将代码移出构造函数将有助于设计师。 - Quibblesome
3个回答

2
这是反编译代码,本例中stateMask是用来标识选定项状态的状态掩码。
public object GetItem(int virtualIndex, int stateMask)
{
  int actualIndex = this.GetActualIndex(virtualIndex, stateMask);
  if (actualIndex == -1)
    throw new IndexOutOfRangeException();
  else
    return this.entries[actualIndex].item;
}

因此,一定有些东西正在改变,正如Sriram所指出的,在SelectedItem属性中有以下检查:

public object SelectedItem
{
  get
  {
    if (this.SelectedItems.Count > 0)
      return this.SelectedItems[0];
    else
      return (object) null;
  }
}

所以它在这里有些问题,然后在GetItem处失败。我怀疑是一些线程混乱的问题。


你确定吗?这是反编译代码 public object SelectedItem { get { if (this.SelectedItems.Count > 0) { return this.SelectedItems[0]; } return null; } } - Sriram Sakthivel
是的,那是个好观点,我最初读错了。所以在那个检查和GetItem代码之间一定有什么变化。多线程可能吗? - CodingGorilla
是的,我在评论中问了同样的问题。我怀疑 OP 在另一个线程中进行修改。 - Sriram Sakthivel
我相应地更新了我的答案,尽管现在它不再是一个真正的答案了。谢谢@SriramSakthivel - CodingGorilla
这是WinForm代码,不能有其他线程修改控件,否则会导致不同的异常。 - Quibblesome

2

您不能这样做:

private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
  if (Control.ModifierKeys == Keys.Control || ( Control.ModifierKeys == Keys.Control || e.Button == MouseButtons.Left))
  {
    listBox1.SelectionMode = SelectionMode.MultiExtended;
  }
  else if (e.Button == MouseButtons.Left)
  {
    listBox1.SelectionMode = SelectionMode.One;
  }
}

在MouseDown事件中更改该属性,我认为会销毁窗口并重新创建它,这会影响SelectedIndexChanged事件期间触发的内部信息。

只需注释掉该代码,并在设计时决定ListBox控件应具有的SelectionMode。

您还应确保获取正确的索引值,例如:

index = label4.Text.IndexOf(endTag, start + 1);
if (index > -1) {
  string g = label4.Text.Substring(start, index - start);
  label4.Text = g;
}

不只是“我认为”。在SelectionMode设置器中调用Control.RecreateHandle()! - Quibblesome

1

好的,我已经看了一下,可以得出结论,问题可能不是由您提供给我们的任何代码引起的,而是其他原因。我不相信多线程正在进行,因为在WinForm中进行多线程是非法的,并会导致不同的异常。

你需要做的,user2760148,是提供给我们一个小但完整的示例。创建一个新项目,并使用最少的代码实现相同的结果。

你的第一步应该是硬编码列表框的数据,并只有鼠标按下事件处理程序。然后逐渐添加你的代码,直到找到问题所在。很有可能你会自己发现问题...至少你会找到导致问题的步骤。目前,在这个示例中有太多的“噪音”,我们很难轻易地找到具体的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接