ilostmyid2 Ответов: 2

970827 - исключение unexcepted происходит, когда я называю datarowcollection с.добавить


В следующем коде:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SQLite;
using System.Diagnostics;

namespace WindowsFormsApplication1
{
    public partial class List : Form
    {
        public List()
        {
            InitializeComponent();
        }

        private void List_Load(object sender, EventArgs e)
        {
            comboBox1.SelectedIndex = 1;
		}

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
			var cmd = new SQLiteCommand("select * from students", DB.Connection);
			var ad = new SQLiteDataAdapter(cmd);
			var dt = new DataTable();
			ad.Fill(dt);
			listBox1.DataSource = dt;
			listBox1.DisplayMember = "name";
		}

		private void btnAdd_Click(object sender, EventArgs e)
		{
			Debug.Assert(listBox1.DataSource is DataTable);
			var dt = listBox1.DataSource as DataTable;
			dt.Rows.Add();
			btnEdit.Enabled = btnRemove.Enabled = dt.Rows.Count != 0;
		}

		private void btnEdit_Click(object sender, EventArgs e)
		{
			Debug.Assert(listBox1.SelectedItem is DataRowView);
			new StudentsForm2(listBox1.SelectedItem as DataRowView).ShowDialog(this);
		}

		private void btnRemove_Click(object sender, EventArgs e)
		{
			Debug.Assert(listBox1.DataSource is DataTable);
			var dt = listBox1.DataSource as DataTable;
			dt.Rows.RemoveAt(listBox1.SelectedIndex);
			btnEdit.Enabled = btnRemove.Enabled = dt.Rows.Count != 0;
		}

		private void List_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Escape)
			{
				Close();
			}
		}

    }
}

когда таблица пуста, я получаю следующее исключение:
Цитата:
Первое случайное исключение типа 'System.Об' произошли в системе.Окна.Forms.dll

Дополнительная информация: InvalidArgument=значение '0' недопустимо для 'SelectedIndex'.

в методе btnAdd_Click при вызове dt.Rows.Add(). comboBox1 содержит имена таблиц, но поскольку на данный момент у меня есть только одна таблица, она не используется, если только не вызывается comboBox1_SelectedIndexChanged.

Вот трассировка стека в точке, где генерируется исключение:
Цитата:
в системе.Среды.GetStackTrace(исключение e, Boolean needFileInfo)
в System.Environment.get_StackTrace()
в системе.Окна.Формы.ListBox.set_SelectedIndex(значение Int32)
в системе.Окна.Формы.Элементе управления listcontrol.DataManager_PositionChanged(объект отправителя, EventArgs в электронной)
в системе.Окна.Формы.CurrencyManager.OnPositionChanged(EventArgs e)
в системе.Окна.Формы.CurrencyManager.ChangeRecordState(типа int32 newPosition, логические проверки, логическое endCurrentEdit, логическое firePositionChange, логический метод pulldata)
в системе.Окна.Формы.CurrencyManager.List_ListChanged(отправитель объекта, ListChangedEventArgs e)
в System.Data.DataView.OnListChanged(ListChangedEventArgs e)
в System.Data.DataView.IndexListChanged(отправитель объекта, ListChangedEventArgs e)
в System.Data.DataView.IndexListChangedInternal(ListChangedEventArgs e)
в System.Data.DataViewListener.IndexListChanged(ListChangedEventArgs e)
в System.Data.Индекс.&ЛТ;&ГТ;гр.&ЛТ;onlistchanged&ГТ;б__88_0(DataViewListener слушателя, ListChangedEventArgs аргументы, логические арг2, логическое значение arg3)
в системе.Данных.Слушателей 1.Уведомить[Т1,Т2,Т3](Т1 арг1, арг2 Т2, Т3 значение arg3, действие 4 Действие)
в System.Data.Индекс.OnListChanged(ListChangedEventArgs e)
в System.Data.Индекс.OnListChanged(ListChangedType changedType, индекс Int32)
в System.Data.Индекс.InsertRecord(Int32 record, Boolean fireEvent)
в System.Data.Индекс.ApplyChangeAction(типа int32 записи, типа int32 действий, типа int32 changeRecord)
в System.Data.Индекс.RecordStateChanged(типа int32 записи, dataviewrowstate вместе oldstate содержат, dataviewrowstate вместе новогогосударственного)
в System.Data.DataTable.RecordStateChanged(типа int32 истории1, dataviewrowstate вместе oldState1, dataviewrowstate вместе newState1, int32 и record2, dataviewrowstate вместе oldState2, dataviewrowstate вместе newState2)
в System.Data.DataTable.SetNewRecordWorker(Строкаданных подряд, типа int32 proposedRecord, DataRowAction действий, логическое isInMerge, логическое suppressEnsurePropertyChanged, установки типа int32, boolean значение кнопкуfireevent, исключение&амп; deferredException)
в System.Data.DataTable.Метод insertrow(Строкаданных подряд, типа int64 proposedID, int32 значение поз, логическое кнопкуfireevent)
в System.Data.DataRowCollection.Добавить(Object[] values)
в WindowsFormsApplication1.List.btnAdd_Click(отправитель объекта, EventArgs e) в C:\Users\hamidi\Documents\Visual Studio 2010\Projects\m_rezaee\WindowsFormsApplication1\WindowsFormsApplication1\List.cs:строка 44
в системе.Окна.Формы.Контроль.OnClick(EventArgs e)
в системе.Окна.Формы.Кнопка.OnClick(EventArgs e)
в системе.Окна.Формы.Кнопка.OnMouseUp(MouseEventArgs mevent)
в системе.Окна.Формы.Контроль.WmMouseUp(Message& m, кнопка MouseButtons, Int32 клика)
в системе.Окна.Формы.Контроль.WndProc(сообщение& m)
в системе.Окна.Формы.ButtonBase.WndProc(сообщение& m)
в системе.Окна.Формы.Кнопка.WndProc(сообщение& m)
в системе.Окна.Формы.Контроль.ControlNativeWindow.OnMessage(сообщение& m)
в системе.Окна.Формы.Контроль.ControlNativeWindow.WndProc(сообщение& m)
в системе.Окна.Формы.Родное окно.DebuggableCallback(hwnd элемента указателя IntPtr, int32 и глутамат натрия, указателя IntPtr параметр wparam, указателя IntPtr lparam должен)
в системе.Окна.Формы.Небезопасные методы.DispatchMessageW(MSG& msg)
в системе.Окна.Формы.Приложение.ComponentManager.Система.Окна.Формы.Небезопасные методы.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
в системе.Окна.Формы.Приложение.ThreadContext.RunMessageLoopInner(Int32 причина, контекст ApplicationContext)
в системе.Окна.Формы.Приложение.ThreadContext.RunMessageLoop(Int32 причина, контекст ApplicationContext)
в системе.Окна.Формы.Application.Run(форма mainForm)
в WindowsFormsApplication1.Program.Main() in C:\Users\hamidi\Documents\Visual Studio 2010\Projects\m_rezaee\WindowsFormsApplication1\WindowsFormsApplication1\Program.cs:строка 18
в системе.AppDomain._nExecuteAssembly(сборка RuntimeAssembly, String[] args)
в системе.домен приложений.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
в корпорации Microsoft.VisualStudio.Хостингпроцесс.HostProc.RunUsersAssembly()
в системе.Нарезание резьбы.ThreadHelper.ThreadStart_Context(состояние объекта)
в системе.Нарезание резьбы.Параллельном режиме.RunInternal(параллельном режиме параллельном режиме, ContextCallback обратного вызова, состояние объекта, логическое preserveSyncCtx)
в системе.Нарезание резьбы.Параллельном режиме.Выполнения(в параллельном режиме параллельном режиме, ContextCallback обратного вызова, состояние объекта, логическое preserveSyncCtx)
в системе.Нарезание резьбы.Параллельном режиме.Выполнения(в параллельном режиме параллельном режиме, ContextCallback обратного вызова, состояние объекта)
в системе.Нарезание резьбы.ThreadHelper.ThreadStart()


Что я уже пробовал:

Я не мог найти ни малейшего намека на то, почему это происходит.

Eric Lynch

Если вы выполняете это в отладчике, это должно помочь вам изолировать точную строку, в которой происходит исключение. Обмен этой информацией может помочь нам помочь вам.

Хотя это и не причина вашей проблемы, я все же отмечу одну вещь, которую вы должны исправить. Многие классы являются IDisposable (например, SQLiteCommand и SQLiteDataAdapter). В общем случае, если класс IDisposable, вы должны либо обернуть его в оператор "using", либо в конечном итоге вызвать метод Dispose. В противном случае произойдет утечка ресурсов.

Еще один thing...it маловероятно, что в List_Load, когда вы устанавливаете значение comboBox.SelectedIndex равняется 1, что это допустимое значение. Во время загрузки формы, если вы предварительно не заполнили поле со списком, это будет недопустимо, так как поле со списком будет пустым. Значение 1 означает, что существует по крайней мере два элемента. Значение 0 означает, что существует хотя бы один элемент. Когда никаких элементов нет, SelectedIndex традиционно равен -1, хотя вы также не должны устанавливать его в это значение.

ilostmyid2

Спасибо Эрику за то, что он нашел время для изучения моего кода и ваших заметок о нем. Я обновил вопрос и добавил трассировку стека в точке, указанной отладчиком в качестве источника исключения. Я надеюсь, что эта информация может помочь. Как я уже говорил, компилятор указывает на то, что исключение находится в строке, которую я вызываю dt.Rows.Add().
Что касается утилизации IDisposable объектов, Я думал, что GC будет утилизировать их позже. Ты хочешь сказать, что это не так?
Что касается содержимого combobox, то я заполняю его двумя элементами в .Designer.

Eric Lynch

Отладчик обычно указывает вам на точную линию немного проще...отсюда и предположение. Мне немного хочется спать, так что завтра я должен буду взглянуть на трассировку стека.

Что касается GC, то он отлично справляется с рекультивацией выделенных ресурсов memory...at какой - то момент после того, как экземпляры выходят из области видимости.

IDisposable решает другую проблему. С IDisposable часто существует неуправляемый ресурс (сетевое соединение, дескриптор файла и т. д.), связанный с экземпляром. ГК редко делает что-либо, чтобы вернуть эти ресурсы. Таким образом, если класс реализует IDisposable, вам действительно следует вызвать метод Dispose (обычно неявно через оператор using), чтобы избежать утечки этих ресурсов.

Честно говоря, эта очистка часто (не всегда) является немного устаревшим багажом на границе того, где начинался .NET и продолжались традиционные API windows.

C# действительно полезен в этом отношении. Оператор using гарантирует, что удаление происходит даже при наличии исключений. Конечно, вы всегда можете использовать блоки try/finally и вызывать Dispose самостоятельно, чтобы достичь аналогичного, но менее краткого результата :)

Eric Lynch

Я взглянул на вашу трассировку стека и должен признаться, что немного озадачен. Из трассировки стека, как Вы упомянули, исключение, по-видимому, происходит во время вызова dt.Rows.Add. Этот вызов по какой-то причине внутренне приводит к изменению выбранного индекса для некоторого списка (возможно, listBox1). Однако к моменту этого вызова что-то изменилось таким образом, что предложенное значение индекса больше не является допустимым.

Я попытался воспроизвести обстоятельства с помощью своего собственного кода, но не смог. Кажется, есть что-то, что не очевидно в коде, которым вы поделились.

Так что, к сожалению, мне остается только гадать. Я думаю, что это может быть трудно отладить.

Моя первая догадка заключается в том, что, как и вы, я упускаю что-то очевидное. Если это так, то я могу оказаться не тем, кто вам поможет :)

Другая возможность заключается в том, что у вас есть неправильно подключенное событие. Я бы проверил все события на наличие компонентов в вашей форме, чтобы убедиться, что все они подключены к ожидаемому вами методу. Кроме того, возможно, стоит улучшить ваш вопрос, чтобы поделиться этой проводкой. Это не очевидно в вашем коде.

Еще одно предположение: возможно, вы не делитесь всем текущим или релевантным кодом для своей формы? Я бы проверил это и улучшил ваш вопрос, если это необходимо.

Затем я позабочусь о низко висящих фруктах. Убирай, что можешь. Например, утилизируйте там, где вам следует утилизировать. Также рассмотрим строку dt.Rows.Add(). Это действительно то, что ты собираешься сделать? Добавить строку, в которой все значения столбцов равны нулю? Это кажется странным.

Кроме того, связь между вашим списком и списком кажется необычной. Когда поле со списком изменяется, вы меняете источник данных для списка. Похоже, что вы обновляете список полностью независимо от нового значения индекса для поля со списком. Это необычно.

Кроме того, в отладчике я бы установил разрывы в каждом отдельном методе в вашей форме. Может быть, кто-то звонит в то время, когда вы этого не ожидаете?

Я бы использовал отладчик, чтобы внимательно взглянуть на ваш DataTable. Есть ли в нем ожидаемые столбцы с ожидаемыми значениями и ожидаемыми ограничениями?

По общему признанию, предложенная очистка кода вряд ли исправит вашу проблему. Однако чем больше переменных вы можете исключить, тем легче отслеживать проблему.

Наконец, если вы достигнете точки отчаяния, в качестве последнего средства, есть еще один трюк, который я нашел полезным в этих ситуациях. Начните комментировать код, пока ваша проблема не исчезнет. Затем вернитесь назад, раскомментировав, пока не выясните минимальный код, необходимый для его воспроизведения. Это может, по крайней мере, сузить то, что вам нужно рассмотреть, чтобы исправить это.

Надеюсь, что-то из этого поможет или кто-то другой увидит очевидное и укажет на это.

ilostmyid2

В первом абзаце я предпочитаю "еще нет", а не "уже нет". Возможно, это произойдет до того, как элемент будет полностью добавлен в список. Во втором и третьем абзацах я говорю, что, возможно, это ошибка, а не проблема в моем коде.
Я не мог найти ваш смысл в проводном или неправильно проводном событии. Если потребуется какая-то другая информация, скажите мне, чтобы я поделился ею.
Вызываю dt.Rows.Add-это метод, который добавляет столбцы со значениями по умолчанию, а не null!
Да, я меняю источник данных списка с изменением индекса combobox, потому что combobox содержит имена таблиц, и очевидно, что при изменении таблицы в списке должна отображаться новая структура.
Я тоже так думал. Поэтому я поставил отладку.WriteLine, где, как я думал, может быть вызван во время вызова dt.Rows.Add(). Но я обнаружил, что никакие другие части моего кода не вызываются.
Что касается DataTable, то в этой функции нет явного ожидания. Колонны могут быть какими угодно. Хотя они в хорошем состоянии, это не может быть источником проблемы.
Поскольку другие части моего кода не вовлекаются логически и практически во время вызова dt.Rows.Добавим, что упрощение их никак не может повлиять на симптом.
Спасибо, что предложили метод комментирования кода. Это работает из-за упрощения, о котором я упоминал. Но, как я уже сказал, в данном случае это не поможет.
В конце концов, я беспокоюсь о том, что это ошибка. Когда я гуглил его, кто-то предложил добавить обработчик для SelectedIndexChanged после вызова dt.Rows.Добавь, хотя это все равно не называется!

Eric Lynch

Что касается "я беспокоюсь о том, что это ошибка"...Не волнуйтесь, это определенно ошибка...если только вы не намеревались сделать исключение :)

Если серьезно, то многие предложения должны были помочь вам бороться с предположениями. Когда вы пытаетесь решить такую запутанную проблему, как эта, предположения-ваш самый большой враг.

Позвольте мне привести вам пример: "другие части моего кода не участвуют логически". Если бы ваш код работал так, как вы предполагали, это было бы безопасным предположением. К сожалению, код не работает. Происходит что-то, чего никто из нас не понимает. Учитывая это, вы больше не можете безопасно делать это предположение.

Вот что я знаю наверняка...путем экспериментов...а не предположений. Я написал код, с нуля, который был настолько близок к вашему, насколько это было возможно. У него не было такой же проблемы. Итак, то, что вы пытаетесь сделать, абсолютно возможно. Что-то неочевидное в вашем коде вызывает другое поведение (исключение).

Возможно, вы захотите вернуться к моим предыдущим предложениям, не отвергая их так легко на этот раз. Если вы хотите решить эту проблему, единственное предположение, которое вы можете сделать, - это то, что вы "ничего не знаете". :) Вам нужно будет подтвердить все с помощью наблюдений или экспериментов.

Что касается значения "mis-wired events"...каждый из компонентов ваших форм (Button, ComboBox, ListBox и т. д.) имеет целую кучу возможных событий (например, Click), которые связаны (wired) с данным методом (например, btnAdd_Click). В идеале каждое событие подключается к тому методу, который вы предполагали.

К сожалению, это тот случай, когда поведение не очевидно в коде, которым вы поделились. Я видел случаи, когда событие, либо из-за человеческой ошибки, либо из-за повреждения проекта, становится связанным с непреднамеренным методом. Это может вызвать очень странное поведение. Вы можете проверить, как связаны события, щелкнув по каждому из компонентов и посмотрев на вкладку событие в свойствах.

Я предлагаю улучшить ваш вопрос, чтобы разделить все эти ассоциации (между событием и методом).

Это пример того, где предположения могут повредить вам. Вы "предполагаете", что все ваши события правильно связаны, но пока вы не перепроверите, вы не можете быть уверены.

Если хотя бы одно событие неправильно подключено, закомментирование кода или установка точек останова во всех методах-это методы, которые могли бы помочь вам обнаружить проблему. Эти же методы могут помочь выявить и другие неверные предположения.

За другими предположениями стоят аналогичные причины, накопленные примерно за три десятилетия опыта. Я бы объяснил каждый из них, но чувствую, что этот ответ уже приближается к романной длине :)

Однако я повторю одно предложение. Пожалуйста, дважды проверьте, что код, которым вы поделились, является полным и идентичным тому, что вы на самом деле запускаете. Я знаю, что это звучит глупо, но в прошлом я пытался помочь кому-то только для того, чтобы гораздо позже обнаружить, что мы не отлаживали один и тот же код.

Один footnote...it на самом деле ожидаемое поведение, которое SelectedIndexChanged не вызывается. Система.Окна.Формы.ListBox.set_SelectedIndex, который изменяет индекс, терпит неудачу. SelectedIndexChanged (прошедшее время) вызывается после изменения индекса, которое никогда не происходит из-за сбоя.

Eric Lynch

FWIW, вот аналогичный код, с которым я экспериментировал (который отлично работает). Я также перепробовал почти все, что мог придумать, чтобы заставить его потерпеть неудачу подобным же образом (без успеха).

использование системы;
использование System.Data;
использование системы.Окна.Формы;

пространство имен CodeProjectQAForms
{
public partial class MainForm : форма
{
public MainForm() =>
метод InitializeComponent();

частная идентификатор инт ;

частная addButton_Click недействительным(объект отправителя, EventArgs в электронной)
{
ВАР таблице = список listbox1.Источником данных объекта DataTable;
if (table == null)
вернуть;

стол.Строк.Добавить((++код).Метод toString());
// table.Rows.Add(); // также попробовал это сделать

нажмите кнопку Изменить.Включено = removeButton.Включено = таблица.строки.Count > 0;
}

частная MainForm_Load недействительным(объект отправителя, EventArgs в электронной)
{
var table = new DataTable();
стол.Столбцы.Add("name", typeof(string));

список listbox1.Источник данных dataSource = таблица;
listBox1.DisplayMember = "имя";
}
}
}

ilostmyid2

Thanks Eric for your description and effort is this problem. I believe in most of what you say and don't know what to say more. I also reviewed your code and don't know why it should work properly and mine doesn't. I'm also an experienced programmer and have had many challenges mostly with unmanaged codes in C/C++. I think we don't have to worry about most of them in managed codes like this, although it persist on 'most'. Anyway, after some investigations, I found some clues which I describe as a separate solution as it worked for me in such cases. I found it on StackOverflow.com. Still though, the problem is there and we may never find why it happens.

2 Ответов

Рейтинг:
4

ilostmyid2

В Visual Studio 2010, когда отладчику говорят остановиться на всех исключениях, он делает это независимо от того, обрабатывается ли исключение или нет. Например, если вы пишете такой код:

try
{
  throw new Exception("test");
}
catch
{
  // do nothing
}

отладчик останавливается на строке, которая выдает исключение, даже если оно поймано и обработано. Обратите внимание, что это также происходит, если исключение создается внутри кодов, которые не принадлежат нашим собственным. Мы можем называть методы классов, которые мы не написали, и мы просто используем их. Методы могут быть написаны таким образом, чтобы обрабатывать исключения и делать что-то в ответ. Если вы вызываете все приложение в этом случае, вы не получите исключение, потому что оно обрабатывается внутри методов. Но если вы запускаете их через отладчик, вы видите, что эти исключения выбрасываются.
В этом коде, похоже, такое и происходит. Я предпочитаю не снимать флажок out of range exception из Debug/Exceptions... меню. Я предпочитаю получать информацию, если какая-либо часть моего кода работает плохо. Но такие исключения не должны быть информированы, потому что они должным образом обрабатываются.
Для этого мне нужно:
1. проверьте все исключения в Debug/Exceptions... меню Visual Studio.
2. Установите флажок Включить только мой код (только управляемый) в разделе Инструменты/Параметры/отладка/Общие сведения.
Таким образом, отладчик будет останавливаться только на исключениях, которые генерируются вашим собственным кодом.

PS. я нашел информацию и решение здесь.


Рейтинг:
1

RmcbainTheThird

Ваша трассировка стека уже предоставила вам необходимые подсказки:
C:\Users\hamidi\Documents\Visual Studio 2010\Projects\m_rezaee\WindowsFormsApplication1\WindowsFormsApplication1\Program.cs:строка 18
и
\WindowsFormsApplication1\List.cs:строка 44
Пойди посмотри, что там происходит. вставьте точку останова в эту линию и проверьте используемые там объекты и переменные


ilostmyid2

:)