2009-11-18 14 views
7

Prima di tutto, ho trovato la soluzione all'eccezione. Sono più curioso di perché ha generato l'eccezione specifica che ha fatto.C#, WinForms: ListBox.Items.Add genera una OutOfMemoryException, perché?

Nel mio scenario che sto aggiungendo un POCO ad un ListBox in questo modo:

myListBox.Items.Add(myPOCO); 

Questo stava generando un OutOfMemoryException. Il problema era che ToString dal POCO stava restituendo null. Ho aggiunto un controllo string.IsNullOrEmpty per restituire un valore "sicuro" quando null e l'eccezione è scomparsa.

Perché questo genera un OutOfMemoryException e non qualcos'altro (ad esempio un NullReferenceException)?

MODIFICA: Gli elementi vengono aggiunti in un ciclo for.

Lo stack di chiamata completo (riferimenti specifici dell'azienda rimossi) è riportato di seguito. Una cosa da notare - la casella di riepilogo è vuota quando viene chiamata.

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() 
+1

Stai aggiungendo gli articoli in un ciclo? – scottm

+0

In quali circostanze "ToString" restituisce null? È quando il POCO è straordinariamente grande? –

+0

Per motivi di interesse, puoi pubblicare la traccia dello stack completo dall'eccezione? –

risposta

12

Questo è a causa del modo System.Windows.Forms.ListBox.NativeAdd metodo viene implementato:

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; 
} 

Il metodo utilizza GetItemTextToString() sull'oggetto che restituisce null e così un messaggio viene inviato con il parametro null, che a sua volta restituisce un puntatore non valido e si immette il secondo caso che genera l'eccezione.

+0

Hah, stavo per copiare l'intera fonte del metodo NativeAdd nella mia risposta, ma ho deciso contro ... ho fatto la scelta sbagliata! :-) –

+0

@Justin - Ero distrutto ma penso che sarebbe meglio aiutare qualcun altro che sta riscontrando questo problema. –

+0

nessun problema, una piccola competizione ci rende tutti più intelligenti! :-) –

9

Quando il sottostante LB_ADDSTRING chiamata API di Windows non riesce, WinForms restituisce sempre un OutOfMemoryException. Un commento in .NET Framework Reference Source spiega perché:

// 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)); 
Problemi correlati