【问题标题】:IndexOutOfRange Exception in sqldatareader using c#使用c#的sqldatareader中的IndexOutOfRange异常
【发布时间】:2018-05-04 21:32:18
【问题描述】:

我使用 c# 创建了一个应用程序,在我的身份验证界面中,我有一个测试控件,我想知道配置文件用户。

我的数据库包含名为 user 的表,其中包含 4 列

(id_user,name ,mail, profile) 

这是我的代码

public string profil_user(string login)
    {
        SqlConnection conn = new database().connect_user();
        SqlCommand cmd = conn.CreateCommand();
        cmd.CommandText = "select profile from user where name = '" + login + "';";
        SqlDataReader s = cmd.ExecuteReader();
        if (s.Read())
        {
           return ( s.GetString(3));


        }
        else{return ("false"); }
    }

但我在s.GetString(3) 有一个例外

system.IndexOutOfRange : 索引超出了数组的范围

【问题讨论】:

  • 小鲍比桌打电话
  • s.GetString(0) 因为您只返回了一列。
  • LBT: Citation 需要
  • 您能否澄清一下您实际上是有四行(这似乎不太可能)还是四个

标签: c# sqldatareader


【解决方案1】:

您只选择了一个字段 (profile),但随后您尝试在此处选择第 4 个字段(索引 3):

return ( s.GetString(3));

除了返回s.GetString(0)之外,我强烈建议您:

  • 使用参数化 SQL - 总是这样做,以防止SQL injection attacks,使您的代码更具可读性,并防止意外的文本转换问题
  • 如果未找到配置文件,则抛出异常或返回 null,而不是返回字符串“false”
  • 使用 using 语句表示一次性的东西,例如 SqlCommandSqlConnectionSqlDataReader,以确保您适当地清理资源
  • 开始关注.NET naming conventions,让您的代码更加地道

比如:

public string GetUserProfile(string login)
{
    string sql = select profile from user where name = @login";
    // I assume Connect() returns an *open* connection?
    using (var conn = new Database().Connect())
    {
        using (var command = new SqlCommand(sql, conn))
        {
            command.Parameters.Add("@login", SqlDbType.NVarChar).Value = login;
            using (var reader = command.ExecuteReader())
            {
                // If it's an error (code failure) for there to be no matching profile,
                // you may want to throw an exception instead.
                return s.Read() ? s.GetString(0) : null;
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    所以你想要第四行,而不是你尝试使用s.GetString(3) 访问的第四列:

    int rowNum = 0;
    while(s.Read())
    {
       if(++rowNum == 4)
       {
          return s.GetString(0);
       }
    }
    return "false";
    

    但是,当您不使用Order By 时访问第四行有点奇怪。您还应该只使用正确的 sql 查询返回您想要的行。

    如果您在此处使用字符串连接,您也可以进行 sql 注入:

    cmd.CommandText = "select profile from user where name = '" + login + "';";
    

    使用sql参数:

    cmd.CommandText = "select profile from user where name = @login";
    cmd.Parameters.Add("@login", SqlDbType.VarChar).Value = login;
    

    有 4 列而不是行

    好的,所以您需要第四列。为什么不用这个名字呢?

    由于您只选择profile-列(第四列),您可以简单地使用GetString(0)。但您也可以选择所有列,然后使用GetOrdinal 确定正确的索引:

    int profileColumnIndex = s.GetOrdinal("profile");
    return s.GetString(profileColumnIndex);
    

    如果您不控制查询或将来可能会更改,这很有用。

    【讨论】:

    • 我怀疑 OP 真的 有 4 行。我强烈怀疑他们有四列,而他们只是在问题中写错了内容。
    • 最后一句可以加1+吗?
    • @DaisyShipton:现在我又读了一遍,看来你是对的。他说行,但他显示列。
    【解决方案3】:

    您只选择了 1 个字段,因此索引 3 超出范围。使用参数也很重要。试试:

    cmd.CommandText = "select profile from user where name = @login;";
    cmd.Parameters.Add("@login, SqlDbType.NVarChar).Value = login;
    SqlDataReader s = cmd.ExecuteReader();
    while (s.Read())
    {   
      return  s[0].ToString();
    }
    

    【讨论】:

      【解决方案4】:

      SqlDataReader.GetString 的参数应该是列索引。你只选择一列,所以你得到一个例外。

      【讨论】:

        【解决方案5】:

        因为您的选择列表中没有所有字段

        将 SQL 更改为:

        select id_user,name ,mail, profile from user where name = '" + login + "';
        

        【讨论】:

        • OP 似乎只希望返回一个字段 - 您的建议仍然使代码容易受到 SQL 注入攻击。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-06
        • 2012-04-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多