2011-01-14 103 views
1

我观察到一个奇怪的行为,通过解析字符串到XElement。C# - 解析XElement时的奇怪行为

首先,这里是我想要解析XML:

<return value="0"> 
    <resultset> 
     <meta> 
      <column type="char(30)"></column> 
     </meta> 
     <datarow> 
      <datacol> 
       <![CDATA[master]]> 
      </datacol> 
     </datarow> 
    </resultset> 
</return> 

现在代码:

  try 
      { 
       xmlResult = XElement.Parse(
        _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
        LoadOptions.PreserveWhitespace); 
      } 
      catch 
      { 
       xmlResult = XElement.Parse(
        _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
        LoadOptions.PreserveWhitespace); 
      } 

我做同样的事情在try和catch块。

有时候,try块会引发XmlException(“Root元素丢失”),但catch块(完全一样的东西)不会抛出它并正确解析字符串。

有人能告诉我为什么吗?

谢谢!

[编辑]

这里是整个方法的代码:

private TcpClient _client; 
private NetworkStream _clientStream; 
private MemoryStream _responseBytes; 
private readonly UTF8Encoding _UTF8Encoder = new UTF8Encoding(); 
private const int BUFFER_SIZE = 1024; 

    private XElement Receive() 
    { 
     byte[] buffer = new byte[BUFFER_SIZE]; 

     XElement xmlResult; 
     Encoding serverEncoding = this.Task.Server.Encoding; 

     // Reading result 
     while (true) 
     { 
      _responseBytes = new MemoryStream(); 

      try 
      { 
       IAsyncResult e = _clientStream.BeginRead(buffer, 
        0,            // Begin 
        BUFFER_SIZE,         // Length 
        new AsyncCallback(OnBeginRead),     // Callback used 
        new SocketAsyncState(_clientStream, buffer)); // Passing buffer to callback 

       e.AsyncWaitHandle.WaitOne(); // Wait until data are in pipe 

       if (((SocketAsyncState)e.AsyncState).HasError) 
       { 
        throw new ObjectDisposedException(); 
       } 

       // Try to convert to a XElement, if fail, redo all process. 
       _responseBytes.Position = 0; 

       try 
       { 
        xmlResult = XElement.Parse(
         _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
         LoadOptions.PreserveWhitespace); 
       } 
       catch 
       { 
        xmlResult = XElement.Parse(
         _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
         LoadOptions.PreserveWhitespace); 
       } 

       // Result 100% retrieved : quit loop 
       break; 
      } 
      catch (Exception ex) 
      { 

       if (ex is ObjectDisposedException 
        || ex is XmlException) 
       { 
        while (!IsConnected) { Wait(); } // Wait that the network comes back 
        SendSyn();       // Relaunch process 
       } 
      } 
     } 

     // Result 100% retrieved : send ACK to Socket 
     SendAck(); 

     return xmlResult; 
    } 

    private void OnBeginRead(IAsyncResult ar) 
    { 
     SocketAsyncState state = ar.AsyncState as SocketAsyncState; 
     byte[] nextBuffer = new byte[BUFFER_SIZE]; 
     int numberOfBytesReaded; 
     Encoding serverEncoding = this.Task.Server.Encoding; 

     try 
     { 
      numberOfBytesReaded = state.Stream.EndRead(ar); 
     } 
     catch(Exception) 
     { 
      ((SocketAsyncState)ar.AsyncState).HasError = true; 
      // Quit 
      return; 
     } 

     // While data are available, read next buffer (recursive call to this method) 
     if (state.Stream.DataAvailable && state.Stream.CanRead) 
     { 
      state.Stream.BeginRead(nextBuffer, 
       0, 
       BUFFER_SIZE, 
       new AsyncCallback(OnBeginRead), 
       new SocketAsyncState(state.Stream, nextBuffer)); 
     } 

     // Default C# strings are in UTF-8, so convert stream only if needed 
     if (serverEncoding.CodePage != _UTF8Encoder.CodePage) 
     { 
      byte[] buffer = Encoding.Convert(serverEncoding, 
       _UTF8Encoder, 
       state.Data.TakeWhile((b) => b != '\0').ToArray()); 

      _responseBytes.Write(buffer, 0, buffer.Length); 
     } 
     else 
     { 
      _responseBytes.Write(state.Data, 0, numberOfBytesReaded); 

     } 
    } 

回答

3

你还没有告诉我们什么_responseBytes是,但一个建议弹簧记:如果它被异步填充(例如,通过一个异步Web请求),那么可能第一次尝试发生在数据存在之前,但在catch块执行时,数据已经到达。

(显然,如果是这样的话,解决的办法是使用这种catch块,但以固定的时间。)

编辑:好的,我想我可能看到的问题。它在这里:

e.AsyncWaitHandle.WaitOne(); 

我怀疑会等到读已在套接字级别发生,但回调之前被调用。你的代码假设它等到回调有完成

所以发生了什么(这仍然只是一个猜测)是:

  • 在你的主线程,您揭开序幕的操作,并等待它完成
  • 的数据读取
  • WaitOne()在主线程中返回,同时在线程池线程上调用回调
  • 您试图从主线程中解析内存流中的数据...
  • ... an d 然后回调实际上是将数据写入内存流
  • ...和然后你有第二次尝试解析,其成功,因为数据是现在有
+0

请参阅编辑。你是对的,所有的都是异步完成的,但是似乎很奇怪MemoryStream没有被填充...... – 2011-01-14 11:56:44