System.Collections.Generic.List <t> .ToArray()和System.Linq.Enumerable.ToArray <t>()之间的区别?</t> </t>

时间:2012-05-08 07:37:10

标签: c# wcf linq web-services soap

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

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服务之后,该调用产生了一个错误的请求&#34;异常。

最终我发现了.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)Bad Request。

堆栈跟踪:

  

服务器堆栈跟踪:

     

at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request,HttpWebResponse response,HttpChannelFactory factory,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超时)

     

at 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 operation)

     

在System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

&GT;

  

在[0]处重新抛出异常:

     

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

     

at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&amp; msgData,Int32 type)

     

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

     

在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。

     

位于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(消息&amp; m,MouseButtons按钮,Int32点击)

     

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

     

在DevExpress.Utils.Controls.ControlBase.WndProc(消息&amp; m)

     

at DevExpress.XtraEditors.BaseControl.WndProc(Message&amp; msg)

     

在System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message&amp; m)

     

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

     

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

     

在System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG&amp; msg)

     

at 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)

     

at 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()

1 个答案:

答案 0 :(得分: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> {/ 1>}

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 List实现。