簡體   English   中英

System.Collections.Generic.List之間的區別 <T> .ToArray()和System.Linq.Enumerable.ToArray <T> ()?

[英]Difference between System.Collections.Generic.List<T>.ToArray() and System.Linq.Enumerable.ToArray<T>()?

我最近遇到了一個我正在使用的某種Web方法的問題:

void CheckGfiHelpdesks(string ticket, GfiCheck[] newHelpdeskChecks, GfiCheck[] otherChecks)

我用這段代碼一直在調用這個方法:

List<GfiCheck> newFailedChecks = new List<GfiCheck>();

List<GfiCheck> otherFailedChecks = new List<GfiCheck>();

//do some work, create new GfiCheck items, fill the lists

Webclient.CheckGfiHelpdesks(Ticket, newFailedChecks.ToArray(), otherFailedChecks.ToArray());

newFailedChecks和otherFailedChecks是List。 當方法在IIS上作為SOAP服務運行時,這一直正常工作。

但是,在將完全相同的方法復制到WCF服務后,該調用產生了“400錯誤請求”異常。

最終我發現了.ToArray()確實是問題所在。 這個:

Webclient.CheckGfiHelpdesks(Ticket, newFailedChecks.ToArray<GfiCheck>(), otherFailedChecks.ToArray<GfiCheck>());

即使用System.Linq.Enumerable.ToArray<T>()而不是System.Collections.Generic.List<T>.ToArray()最終解決了問題,異常消失了。

這種差異的解釋是什么? 數組是一個數組,但顯然不是?

確切的例外是:

System.ServiceModel.ProtocolException

遠程服務器返回意外響應:(400)錯誤請求。

堆棧跟蹤:

服務器堆棧跟蹤:

在System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest請求,HttpWebResponse響應,HttpChannelFactory工廠,WebException responseException,ChannelBinding channelBinding)

at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)

在System.ServiceModel.Channels.RequestChannel.Request(消息消息,TimeSpan超時)

在System.ServiceModel.Dispatcher.RequestChannelBinder.Request(消息消息,TimeSpan超時)

在System.ServiceModel.Channels.ServiceChannel.Call(String action,Boolean oneway,ProxyOperationRuntime operation,Object [] ins,Object [] outs,TimeSpan timeout)

在System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall,ProxyOperationRuntime操作)

在System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage消息)

>

在[0]處重新拋出異常:

在System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,IMessage retMsg)

在System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&msgData,Int32 type)

在MonitoringService.BL.CentronService.ICentronService.CheckGfiHelpdesks(String ticket,GfiCheck [] newHelpdeskChecks,GfiCheck [] otherChecks)

at MonitoringService.BL.CentronService.CentronServiceClient.CheckGfiHelpdesks(String ticket,GfiCheck [] newHelpdeskChecks,GfiCheck [] otherChecks)在C:\\ Users \\ sohrm \\ documents \\ visual studio 2010 \\ Projects \\ MonitoringService \\ MonitoringService.BL \\ Service References \\ CentronService \\ Reference.cs:Zeile 5368。

在C:\\ Users \\ sohrm \\ documents \\ visual studio 2010 \\ Projects \\ MonitoringService \\ MonitoringService.BL \\ ConnectorBL.cs:Zeile 120中的MonitoringService.BL.ConnectorBL.CheckHelpdesks(List`1客戶端)。

在C:\\ Users \\ sohrm \\ documents \\ visual studio 2010 \\ Projects \\ MonitoringService \\ MonitoringService.Client \\ MainForm.cs:Zeile 124中的MonitoringService.WinForm.MainForm.LoadChecks()處。

在C:\\ Users \\ sohrm \\ documents \\ visual studio 2010 \\ Projects \\ MonitoringService \\ MonitoringService.Client \\ MainForm.cs:Zeile 114中的MonitoringService.WinForm.MainForm.btnLoad_Click(Object sender,EventArgs e)。

在System.Windows.Forms.Control.OnClick(EventArgs e)

在DevExpress.XtraEditors.BaseButton.OnClick(EventArgs e)

在DevExpress.XtraEditors.BaseButton.OnMouseUp(MouseEventArgs e)

在System.Windows.Forms.Control.WmMouseUp(Message&m,MouseButtons按鈕,Int32單擊)

在System.Windows.Forms.Control.WndProc(Message&m)

在DevExpress.Utils.Controls.ControlBase.WndProc(Message&m)

在DevExpress.XtraEditors.BaseControl.WndProc(消息和消息)

在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.UnsafeNativeMethods.DispatchMessageW(MSG&msg)

在System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID,Int32 reason,Int32 pvLoopData)

在System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason,ApplicationContext context)

在System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason,ApplicationContext context)

在System.Windows.Forms.Application.Run(Form mainForm)

在C:\\ Users \\ sohrm \\ documents \\ visual studio 2010 \\ Projects \\ MonitoringService \\ MonitoringService.Client \\ Program.cs:Zeile 22中的MonitoringService.WinForm.Program.Main()處。

在System.AppDomain._nExecuteAssembly(RuntimeAssembly程序集,String [] args)

在System.AppDomain.ExecuteAssembly(String assemblyFile,Evidence assemblySecurity,String [] args)

在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()

在System.Threading.ThreadHelper.ThreadStart_Context(對象狀態)

at System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback callback,Object state,Boolean ignoreSyncCtx)

在System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回調,對象狀態)

在System.Threading.ThreadHelper.ThreadStart()

System.Collections.Generic.List<T>.ToArray()System.Linq.Enumerable.ToArray<T>()之間應該沒有區別。 讓我們看看里面發生了什么:

System.Collections.Generic.List<T>只是創建新數組並將內部項數組復制到它:

public T[] ToArray()
{
    T[] destinationArray = new T[this._size];
    Array.Copy(this._items, 0, destinationArray, 0, this._size);
    return destinationArray;
}

System.Linq.Enumerable無法訪問列表的內部項數組,因此它通過緩沖區創建數組:

public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)    
        throw Error.ArgumentNull("source");

    Buffer<TSource> buffer = new Buffer<TSource>(source);
    return buffer.ToArray();
}

緩沖區內發生了什么? List<T>ICollection<T>因此它只調用List<T> CopyTo實現:

internal Buffer(IEnumerable<TElement> source)
{
   TElement[] array = null;
   ICollection<TElement> is2 = source as ICollection<TElement>;
   length = is2.Count;
   if (length > 0)
   {
       array = new TElement[length];
       // implemented as Array.Copy(this._items, 0, array, 0, this._size);
       is2.CopyTo(array, 0);
   }

   this.items = array;
   this.count = length;
}

如您所見,通過列表的方法CopyTo將項目復制到新數組,這與ToArray方法內部完全相同。 但是使用System.Linq.Enumerable你有一個小缺點 - 將列表項復制到緩沖區后,創建另一個數組,並將緩沖區中的項復制到該數組:

internal TElement[] ToArray()
{
   if (this.count == 0)        
       return new TElement[0];

   if (this.items.Length == this.count)        
       return this.items;

   TElement[] destinationArray = new TElement[this.count];
   Array.Copy(this.items, 0, destinationArray, 0, this.count);
   return destinationArray;
}

因此,在這兩種情況下,列表中的項目都通過相同的方法Array.Copy復制到新數組。 但是在Enumerable情況下,這發生了兩次。 如果我處理List我寧願使用list的ToArray實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM