3

我最近在使用某种网络方法时遇到了很大的问题:

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 是列表。当该方法作为 SOAP 服务在 IIS 上运行时,这一直运行良好。

但是,在我将完全相同的方法复制到 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 通道绑定)

在 System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(时间跨度超时)

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

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

在 System.ServiceModel.Channels.ServiceChannel.Call(字符串操作,布尔单向,ProxyOperationRuntime 操作,Object[] 输入,Object[] 输出,TimeSpan 超时)

在 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 类型)

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

在 C:\Users\sohrm\documents\visual studio 2010\Projects\MonitoringService\MonitoringService.BL\Service References\CentronService 中的 MonitoringService.BL.CentronService.CentronServiceClient.CheckGfiHelpdesks(String ticket, GfiCheck[] newHelpdeskChecks, GfiCheck[] otherChecks) \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 clients)。

在 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(消息和 m,MouseButtons 按钮,Int32 点击)

在 System.Windows.Forms.Control.WndProc(消息和 m)

在 DevExpress.Utils.Controls.ControlBase.WndProc(消息和 m)

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

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

在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(消息和 m)

在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam)

在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(味精和味精)

在 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.Forms.Application.Run(窗体 mainForm)

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

在 System.AppDomain._nExecuteAssembly(RuntimeAssembly 程序集,字符串 [] 参数)

在 System.AppDomain.ExecuteAssembly(字符串 assemblyFile,证据 assemblySecurity,String [] args)

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

在 System.Threading.ThreadHelper.ThreadStart_Context(对象状态)

在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔 ignoreSyncCtx)

在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态)

在 System.Threading.ThreadHelper.ThreadStart()

4

1 回答 1

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这种情况发生两次。如果我ToArray处理List.

于 2012-05-08T08:24:09.377 回答