2012-05-08 118 views
3

我最近有相當多的問題具有一定的Web方法我用:System.Collections.Generic.List之間的區別<T> .ToArray()和System.Linq.Enumerable.ToArray <T>()?

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(消息消息,時間跨度超時)

在System.ServiceModel.Dispatcher.RequestChannelBinder.Request(消息消息,時間跨度超時)

在System.ServiceModel .Channels.ServiceChannel.Call(String action,單向布爾值,ProxyOperationRuntime操作,Object [] ins,Object []輸出,TimeSpan超時)

at System.ServiceModel.Channels.ServiceChannelProxy。InvokeService(IMethodCallMessage包括MethodCall,ProxyOperationRuntime操作)

在System.ServiceModel.Channels.ServiceChannelProxy.Invoke(即時聊天消息)[0]時

>

異常重新拋出:

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

在System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData & MSGDATA,的Int32類型)

在MonitoringService.BL.CentronService.ICentronService.CheckGfiHelpdesks(字符串票,GfiCheck [] newHelpdeskChecks,GfiCheck [] otherChecks)

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

at MonitoringService.BL.ConnectorBL.CheckHelpdesks(List` C:\ Users \ sohrm \ documents \ visual studio 2010 \ Projects \ MonitoringService \ MonitoringService.BL \ ConnectorBL.cs:Zeile 120.

at MonitoringService.WinForm.MainForm.LoadChecks()in C:\ Users \ sohrm \ documents \ visual studio 2010 \ Projects \ MonitoringService \ MonitoringService.Client \ MainForm.cs:Zeile 124.

at MonitoringService.WinForm.MainForm.btnLoad_Click(Object sender,EventArgs e)in C:\ Users \ sohrm \文檔\ Visual Studio 2010的\項目\ MonitoringService \ MonitoringService.Client \ MainForm.cs:Zeile 114

在System.Windows.Forms.Control.OnClick(E EventArgs的)

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

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

在System.Windows.Forms.Control.WmMouseUp(消息&米,MouseButtons按鈕,點擊的Int32)

在System.Windows.Forms.Control.WndProc(消息&米)

在DevExpress.Utils.Controls.ControlBase.WndProc(消息&米)

在DevExpress.XtraEditors.BaseControl.WndProc(消息& MSG)

在System.Windows.Forms.Control.ControlNativeWindow.OnMessage(消息&米)

在System.Windows.Forms.Control的。 ControlNativeWindow.WndProc(消息& m)上System.Windows.Forms.NativeWindow.DebuggableCallback

(IntPtr的的HWND,MSG的Int32,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原因,的Int32 pvLoopData)

在System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(的Int32原因,ApplicationContext的上下文)

在System.Windows.Forms.Application.ThreadContext.RunMessageLoop(的Int32原因,ApplicationContext的上下文)

在System.Windows 。形成s.Application.Run(Form mainForm)

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

在System.AppDomain._nExecuteAssembly(RuntimeAssembly組件,字串[] args)

在System.AppDomain.ExecuteAssembly(字符串assemblyFile,證據assemblySecurity,字串[] args)

在微軟。 VisualStudio.HostingProcess.HostProc.RunUsersAssembly()

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

在System.Threading.ExecutionContext.Run(的ExecutionContext的ExecutionContext,ContextCallback回調,對象的狀態,布爾ignoreSyncCtx)

在System.Threading.ExecutionContext。運行(執行上下文的ExecutionContext,ContextCallback回調,對象狀態)

在System.Threading.ThreadHelper.ThreadStart()

+0

我覺得你很困惑,沒有'System.Linq.ToArray ()'或'System.Collections.Generic.ToArray()'。 – svick

+0

另外,您可以發佈服務中的完整異常消息和堆棧跟蹤嗎? – svick

+1

您是否意指[System.Linq.Enumerable.ToArray ](http://msdn.microsoft.com/zh-cn/library/bb298736.aspx)和[System.Collections.Generic.List .ToArray]( http://msdn.microsoft.com/en-us/library/x303t819.aspx)? –

回答

1

不應該有差別在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>因此只是調用CopyTo實施List<T>

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,我寧願去與清單的ToArray實施。

+0

順便檢查一下你的服務配置。錯誤的可能原因是最大郵件大小的設置:http://stackoverflow.com/questions/784606/large-wcf-web-service-request-failing-with-400-http-bad-request –

+0

感謝您的所有工作在這個答案中,但事實依然存在:當我將它傳遞給ToArray()時,WCF服務給了我一個例外,但它不與ToArray 。所以說「不應該有什麼區別」在明顯存在的時候並不完全有用。也許問題在於WCF,但是某處存在問題。 – Hackworth

+0

我檢查過了。任何最大郵件大小都會發生異常,並且我已經爲每個數組測試了1個項目。每個GfiCheck項目是一小部分整數和小的字符串,如果是這樣的話,幾個kb。 – Hackworth

相關問題