2012-05-08 122 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

相关问题