C#:当Reader只有一个元素时,我应该使用“if”而不是“while”吗?

时间:2011-12-15 15:46:57

标签: c# loops if-statement

看看这个:

myReader = cmd.ExecuteReader();
if (myReader.HasRows)
{
    while (myReader.Read())
    {
        info = myReader.GetString("info");
        ...
    }
 }
.....

好吧,我不知道为什么,但是当我编译并在另一台PC上使用它时,由于,它会爆炸。但如果我这样做:

myReader = cmd.ExecuteReader();
if (myReader.HasRows)
{
    if (myReader.Read())    <------------------- NOTICE THE IF
    {
        info = myReader.GetString("info");
        ...
    }
 }
.....

......会奏效。请注意,由于程序的逻辑,我知道每次都会只有一个元素

可以这样做吗?它看起来很糟糕,也许不是一个好习惯()。我在问你的方向。

修改: 会发布更多代码,因为可以帮助我找到错误:

 while (myReader.Read())
 {
    info = myReader.GetString("info");
    ...


     /**
      * Write the relevant info in the LOGS
      */
      connection.Close();     <----------   :S  
      connection.Open();      <---------- if I don´t do this I got some problems with the connection!!!!
      string queryLog = "INSERT INTO ....;
      MySqlCommand cmdLog = new MySqlCommand(queryLog, connection);
      cmdLog.ExecuteNonQuery();
 }

7 个答案:

答案 0 :(得分:13)

每当我只想要 一行 时,我都这样做,没有任何问题。

如果我期待单个值,我会改用ExecuteScalar。这将只返回返回的结果集的第一行的第一列中保存的值,通常该集只有一列和一行,因此您不会注意到这一点。

此外,我倾向于不打扰if (myReader.HasRows),因为if (myReader.Read())涵盖了这一点。

我不知道为什么while会导致您发出问题...如果您不是if,我只是提出我对while使用{{1}}的看法。期待多行。

答案 1 :(得分:3)

在不使用while的情况下,您无法检测到读者拥有的元素超出您认为的应有条件的意外情况。随着时间的推移,系统会发生变化,并且随着系统的发展,“读者只会有一个元素”等假设会变得不正确。

如果它对系统的功能或你所编写的代码的功能很重要,那么我仍然会使用while并包含一些只调试构建的代码来断言你真的只收到一个元素。

答案 2 :(得分:3)

我认为if的使用让你的代码的读者清楚地知道你只期望一个项目。您可以在结束后添加断言以捕获逻辑错误,如下所示:

if (myReader.Read())  {
    info = myReader.GetString("info");
    ...
}
Debug.Assert(!myReader.Read(), "Reader has more elements than expected.");

答案 3 :(得分:3)

您确实可以使用if,但您也可以在这种情况下使用while而不会出现错误。只需将其更改为if即可,但如果在可以有多行的情况下执行相同的操作,则会出现相同的错误。因此,重要的是要查看异常发生的原因。

让我们检查你的代码:

while (myReader.Read())
 {
    info = myReader.GetString("info");
    ...

到目前为止一切顺利。

     /**
      * Write the relevant info in the LOGS
      */
      connection.Close();     <----------   :S  
      connection.Open();      <---------- if I don´t do this I got some problems with the connection!!!!
哦,呃!你已经解决了“一些问题”,但是你知道那些“一些问题”是什么吗?实际上你已经破坏了while

在我说“到目前为止这么好”的时候,这就是你发生的事情:

  1. 您有一个连接对象。它是“开放的”。
  2. 您有一个数据读取器对象。它正在从连接中检索数据。
  3. 现在,根据IDbCommand.ExecuteReader(http://msdn.microsoft.com/en-us/library/68etdec0.aspx)的规范,该读卡器正在使用该连接。除非关闭它,否则不允许对该连接执行任何操作,直到您在阅读器上显式或通过Close()致电Dispose(),如果在{{1}中分配了阅读器,则会发生这种情况。阻止。

    现在,严格来说并非总是如此。总是允许给定的实现提供超过接口承诺(无论是根据接口签名还是根据文档)。一旦using返回false(我曾经实现过的唯一一个),许多实现将“释放”连接以便重用,SQLServer 2005有一个Read()选项,允许同一连接同时支持多个datareader立刻(有缺点)。尽管如此,除了这些规则的松动之外,我们现在唯一可以解决的问题是调用MultipleActiveResultSets=True

    出于这个原因,当您尝试调用Close()时,您会以错误消息的形式出现“某些问题”,因为您尝试使用其他用途的连接。

    所以,你通过对连接做的唯一事情 - 关闭它 - 然后再次打开它来“修复”这个。无论出于何种目的,你都会有一个全新的联系!

    现在,当您循环回cmdLog.ExecuteNonQuery()时,它再次调用while。此方法从来自连接的数据流中读取,并返回false(如果没有更多结果)或根据从该流中读取的内容创建一组字段。

    但它没有,因为你关闭了那个连接。所以它“爆炸”有一个例外,因为你试图从一个封闭的连接中读取,而这是无法完成的。

    现在,当您使用myReader.Read()替换此while时,您再也没有回到已被破坏的if操作,因此代码再次运行。

    但如果您需要使用包含多行的结果集,那么您要做什么?

    您可以使用MARS。请参阅http://msdn.microsoft.com/en-us/library/h32h3abf%28v=vs.80%29.aspx。坦率地说,除非事情从中得到更多,否则我会避免它;它有一些微妙的含义,如果你碰到它们可能会让人感到困惑。

    您可以推迟下一次操作,直到关闭读者群。在这种情况下,通过取出不必要的Read()Open(),这只是一个小小的节省:

    Close()

    现在,拥有两个连接而不是一个连接似乎很浪费。但是:

    1. 池化可以非常便宜地创建连接。
    2. 一旦我们执行using(myReader = cmd.ExecuteReader()) { while(myReader.Read()) { string info = myReader.GetString("info"); /* Do stuff */ using(SqlConnection logConn = new SqlConnection(...)) { logConn.Open(); string queryLog = "INSERT INTO ....; MySqlCommand cmdLog = new MySqlCommand(queryLog, connection); cmdLog.ExecuteNonQuery(); } } } ,我们就会将其重新发布到池中,因此如果在很多线程中有很多这种情况发生,那么移动中的连接总数可能会少于线程数的两倍。另一方面,如果只有一个线程这样做,那么只有一个额外的连接,所以谁在乎。
    3. 在提供数据加载器的过程中关闭连接可能会在返回池之前给它额外的清理工作,所以你可能正在使用两个连接(我不知道SQLServer,但我知道有些数据库需要更多的工作才能在这种情况下返回池中。)
    4. 总之,如果不重用它就不能使用连接,这是一个彻头彻尾的错误。通常,一次不能在同一连接上进行多个操作。使用SQLServer2005的ExecuteNonQuery()选项可以实现这一点,尽管它有复杂性。通常,如果您希望一次执行多个DB事务,则应使用多个连接。

      所有这一切,你仍然可以使用MultipleActiveResultSets而不是if,但这样做是因为它是当时有意义的,而不是修复你不理解的错误并拥有它<{1}}无法选择的时候回来。

答案 4 :(得分:1)

您是否妥善处理了连接和阅读器?使用Using,例如:

using (myReader = cmd.ExecuteReader())
{
    if (myReader.HasRows)   
    {   
        while (myReader.Read())   
        {   
            info = myReader.GetString("info");   
            ...   
        }   
    }
}

答案 5 :(得分:0)

我认为你应该仍然使用while,即使你只期望一行,然后在你调用它时使用linq来表达单行期望。您可以使用协程来表达这一点。

public IEnumerable<string> GetInfo() 
{
    // make command and reader...
    while(reader.Read() 
    {
        yield return reader.GetString("info");
    }
 }

然后调用者应该使用Single()方法来表达只有一行的期望。

var info = GetInfo().Single();

答案 6 :(得分:-5)

此代码应添加以下内容以使其返回或不返回行

  myReader = cmd.ExecuteReader();
  myReader.Read();
  if (myReader.HasRows)
  {     
     while (myReader.Read())
     { 
        info = myReader.GetString("info");
     }
  }