C#,WinForms:ListBox.Items.Add生成OutOfMemoryException,为什么?

C#,WinForms:ListBox.Items.Add生成OutOfMemoryException,为什么?,c#,winforms,C#,Winforms,首先,我找到了异常的解决方案。我更好奇的是,为什么它会生成它所做的特定异常 在我的场景中,我向一个列表框中添加一个,如下所示: myListBox.Items.Add(myPOCO); 这正在生成一个OutOfMemoryException。问题是ToString关闭POCO返回null。我添加了一个字符串.IsNullOrEmpty检查,以在null和异常消失时返回一个“安全”值 为什么这会生成一个OutOfMemoryException,而不是其他东西(比如NullReferenceExc

首先,我找到了异常的解决方案。我更好奇的是,为什么它会生成它所做的特定异常

在我的场景中,我向一个列表框中添加一个,如下所示:

myListBox.Items.Add(myPOCO);
这正在生成一个
OutOfMemoryException
。问题是
ToString
关闭POCO返回
null
。我添加了一个
字符串.IsNullOrEmpty
检查,以在null和异常消失时返回一个“安全”值

为什么这会生成一个
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()
System.OutOfMemoryException未处理
Message=“列表框包含的项目太多。”
Source=“System.Windows.Forms”
堆栈跟踪:
位于System.Windows.Forms.ListBox.NativeAdd(对象项)
位于System.Windows.Forms.ListBox.ObjectCollection.AddInternal(对象项)
位于System.Windows.Forms.ListBox.ObjectCollection.Add(对象项)
在\.cs中加载(对象发送方,事件参数e):第52行
在System.Windows.Forms.Form.OnLoad(EventArgs e)中
在System.Windows.Forms.Form.OnCreateControl()中
位于System.Windows.Forms.Control.CreateControl(布尔值不可修改)
在System.Windows.Forms.Control.CreateControl()中
在System.Windows.Forms.Control.WmShowWindow(Message&m)中
位于System.Windows.Forms.Control.WndProc(Message&m)
在System.Windows.Forms.ScrollableControl.WndProc(Message&m)中
在System.Windows.Forms.ContainerControl.WndProc(Message&m)中
在System.Windows.Forms.Form.WmShowWindow(消息和消息)
在System.Windows.Forms.Form.WndProc(Message&m)中
在System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message&m)中
在System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&m)中
在System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd、Int32 msg、IntPtr wparam、IntPtr lparam)
位于System.Windows.Forms.SafeNativeMethods.ShowWindow(HandleRef hWnd,Int32 nCmdShow)
位于System.Windows.Forms.Control.SetVisibleCore(布尔值)
位于System.Windows.Forms.Form.SetVisibleCore(布尔值)
在System.Windows.Forms.Control.set_可见(布尔值)
位于System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32原因,ApplicationContext上下文)
位于System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32原因,ApplicationContext上下文)
在System.Windows.Forms.Application.RunDialog(表单)中
位于System.Windows.Forms.Form.ShowDialog(iwin32窗口所有者)
在System.Windows.Forms.Form.ShowDialog()中
\Program.cs中的at.Program.Main():第25行
位于System.AppDomain.\u nexecutestAssembly(程序集,字符串[]args)
位于System.AppDomain.nExecuteAssembly(程序集,字符串[]args)
at System.Runtime.Hosting.ManifestRunner.Run(布尔checkAptModel)
在System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly()上
在System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext ActivationContext,String[]activationCustomData)中
位于System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext ActivationContext)
位于System.Activator.CreateInstance(ActivationContext ActivationContext)
位于Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone()处
位于System.Threading.ThreadHelper.ThreadStart\u上下文(对象状态)
在System.Threading.ExecutionContext.Run(ExecutionContext ExecutionContext,ContextCallback回调,对象状态)
位于System.Threading.ThreadHelper.ThreadStart()处
当底层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)); 

这是因为
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;
}

该方法对返回
null
的对象使用
ToString()
,因此发送带有
null
参数的消息,这反过来又返回一个无效指针,您将进入引发异常的第二个案例。

如果出现此类错误,请仔细检查调用
listbox.Items.Add
listbox.DataSource=xxxxx
。添加或绑定到列表框的任何
对象
类型必须在
ToString()
方法中返回非Null。默认情况下,如果不重写
ToString()
方法,则.net将返回类型名称

如果您已经实现了自己版本的
ToString()
(带有override关键字),那么请确保该方法具有fail-safe以返回非空字符串。请参阅下面的示例,了解如何添加额外的两行,以避免许多人会发现完全误导的这种奇怪错误

//listbox.Items.Add(new MyItem());
//--or--
//listbox.DataSource= new List<MyItem>(){ new MyItem() };

public class MyItem
{
    public string Name { get; set; }
    public string Label { get; set; }

    public override string ToString()
    {
        //Not adding below 2 lines might throw OutOfMemoryException in listbox.Items.Add or listbox.DataSOurce = somelist
        if (string.IsNullOrEmpty(Label)) //Added this check to avoid 
            return this.GetType().Name; //Return string.Empty or something other than null else you will get OutOfMemoryException error when you add or bind this object to listbox

        return Label;
    }
}
//listbox.Items.Add(new MyItem());
//--或--
//DataSource=new List(){new MyItem()};
公共类MyItem
{
公共字符串名称{get;set;}
公共字符串标签{get;set;}
公共重写字符串ToString()
{
//如果不添加以下两行,则可能会抛出listbox.Items.Add或listbox.DataSOurce=somelist中的OutOfMemoryException
if(string.IsNullOrEmpty(Label))//添加此检查以避免
返回此.GetType().Name;//返回string.Empty或其他非null值,否则在将此对象添加或绑定到listbox时,将出现OutOfMemoryException错误
退货标签;
}
}

是否将项目添加到循环中?在什么情况下,
ToString
将返回null?是在POCO非常大的时候吗?出于兴趣,您可以发布来自异常的完整堆栈跟踪吗?
ToString
返回null,因为我是careles