C #, WinForms: ListBox.Items.Add генерирует исключение OutOfMemoryException, почему? - PullRequest
7 голосов
/ 18 ноября 2009

Во-первых, я нашел решение для исключения. Мне более любопытно , почему он сгенерировал конкретное исключение, которое он сделал.

В моем сценарии я добавляю POCO в ListBox следующим образом:

myListBox.Items.Add(myPOCO);

Это генерировало OutOfMemoryException. Проблема заключалась в том, что ToString из POCO возвращал null. Я добавил string.IsNullOrEmpty проверку, чтобы вернуть «безопасное» значение, когда ноль и исключение исчезли.

Почему это генерирует OutOfMemoryException, а не что-то еще (скажем, NullReferenceException)?

РЕДАКТИРОВАТЬ : Элементы добавляются в цикл for.

Полный стек вызовов (ссылки на компании удалены) приведен ниже. Стоит отметить одну вещь - поле списка пусто, когда это вызывается.

System.OutOfMemoryException was unhandled
  Message="List box contains too many items."
  Source="System.Windows.Forms"
  StackTrace:
       at System.Windows.Forms.ListBox.NativeAdd(Object item)
       at System.Windows.Forms.ListBox.ObjectCollection.AddInternal(Object item)
       at System.Windows.Forms.ListBox.ObjectCollection.Add(Object item)
       at <FORM>_Load(Object sender, EventArgs e) in <PATH>\<FORM>.cs:line 52
       at System.Windows.Forms.Form.OnLoad(EventArgs e)
       at System.Windows.Forms.Form.OnCreateControl()
       at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
       at System.Windows.Forms.Control.CreateControl()
       at System.Windows.Forms.Control.WmShowWindow(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.WmShowWindow(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.SafeNativeMethods.ShowWindow(HandleRef hWnd, Int32 nCmdShow)
       at System.Windows.Forms.Control.SetVisibleCore(Boolean value)
       at System.Windows.Forms.Form.SetVisibleCore(Boolean value)
       at System.Windows.Forms.Control.set_Visible(Boolean value)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.RunDialog(Form form)
       at System.Windows.Forms.Form.ShowDialog(IWin32Window owner)
       at System.Windows.Forms.Form.ShowDialog()
       at <APP>.Program.Main() in <PATH>\Program.cs:line 25
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
       at System.Runtime.Hosting.ManifestRunner.Run(Boolean checkAptModel)
       at System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly()
       at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext, String[] activationCustomData)
       at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext)
       at System.Activator.CreateInstance(ActivationContext activationContext)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

Ответы [ 2 ]

13 голосов
/ 18 ноября 2009

Это из-за способа реализации System.Windows.Forms.ListBox.NativeAdd метода:

private int NativeAdd(object item)
{
    int num = (int) base.SendMessage(0x180, 0, base.GetItemText(item));
    switch (num)
    {
        case -2:
            throw new OutOfMemoryException();

        case -1:
            throw new OutOfMemoryException(SR.GetString("ListBoxItemOverflow"));
    }
    return num;
}

Метод GetItemText использует ToString() для объекта, который возвращает null, поэтому сообщение отправляется с параметром null, который, в свою очередь, возвращает неверный указатель, и вы вводите второй регистр, который выдает исключение.

9 голосов
/ 18 ноября 2009

Когда базовый LB_ADDSTRING вызов Windows API завершается неудачно, WinForms всегда возвращает OutOfMemoryException. Комментарий в справочном источнике .NET Framework объясняет, почему:

// On some platforms (e.g. Win98), the ListBox control
// appears to return LB_ERR if there are a large number (>32000)
// of items. It doesn't appear to set error codes appropriately,
// so we'll have to assume that LB_ERR corresponds to item 
// overflow.
// 
throw new OutOfMemoryException(SR.GetString(SR.ListBoxItemOverflow)); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...