C# Tuple技术问题:如何根据文本框输入动态加载对应测试题目
Hey Nils, let's break down why you're hitting that exception when switching from a hardcoded test name to using textBox1 input, and fix up the code to make it more robust.
The Root Cause of Your Exception
That error when setting radioButton1.Text = list[0].Item1 is almost certainly an IndexOutOfRangeException—meaning your list is empty when you try to access the first element. This happens because either:
- The SQL query didn't return any rows (maybe the test name entered doesn't exist in the database, or there's a typo)
- There was an issue executing the query (like a database connection problem, or invalid SQL syntax from improper string concatenation)
Step-by-Step Fixes & Improvements
1. Use Parameterized SQL to Avoid Errors & SQL Injection
Never directly concatenate user input into SQL queries—it's a huge security risk (SQL injection) and can break your query if the input has spaces, apostrophes, or special characters. Instead, use a parameterized command:
// Replace your hardcoded SQL with this parameterized version string query = @"SELECT item_name FROM TEST_ITEMS I JOIN TESTS T ON I.test_id = T.test_id WHERE test_name = @TestName"; SqlCommand cmd = new SqlCommand(query, con); // Add the parameter from textBox1.Text cmd.Parameters.AddWithValue("@TestName", textBox1.Text.Trim()); // Trim to avoid accidental whitespace
2. Add Error Handling & Check for Empty Results
Before trying to access list[0], make sure the query returned data and your list isn't empty. Wrap the database logic in a try-catch block to catch any connection/query errors:
private void TestF_Load(object sender, EventArgs e) { list = new List<Tuple<string, string>>(); tempTable = new DataTable(); tempTable.Columns.Add("Item1"); tempTable.Columns.Add("Item2"); tempTable.Columns.Add("Value"); var tkey = new DataColumn[] { tempTable.Columns[0], tempTable.Columns[1] }; tempTable.PrimaryKey = tkey; try { // Ensure the connection is open (or use using statements for better resource management) if (con.State != ConnectionState.Open) con.Open(); string query = @"SELECT item_name FROM TEST_ITEMS I JOIN TESTS T ON I.test_id = T.test_id WHERE test_name = @TestName"; SqlCommand cmd = new SqlCommand(query, con); cmd.Parameters.AddWithValue("@TestName", textBox1.Text.Trim()); SqlDataAdapter da = new SqlDataAdapter(cmd); DataTable dt = new DataTable(); da.Fill(dt); // Check if we have any test items if (dt.Rows.Count == 0) { MessageBox.Show($"No test items found for '{textBox1.Text.Trim()}'. Please check the test name."); // Disable radio buttons or handle empty state radioButton1.Enabled = false; radioButton2.Enabled = false; return; } // Generate the binary pairs (optimized loop logic) total = dt.Rows.Count; for (int i = 0; i < total; i++) { for (int j = i + 1; j < total; j++) { list.Add(Tuple.Create( dt.Rows[i]["item_name"].ToString(), dt.Rows[j]["item_name"].ToString() )); } } // Randomize the pairings (you mentioned this in comments—let's implement it!) Random rng = new Random(); list = list.OrderBy(x => rng.Next()).ToList(); // Now safely set the radio button text only if list isn't empty if (list.Count > 0) { radioButton1.Text = list[0].Item1; radioButton2.Text = list[0].Item2; radioButton3.Text = "Undecided"; location++; total = list.Count; } else { MessageBox.Show("No valid item pairs could be generated."); radioButton1.Enabled = false; radioButton2.Enabled = false; } } catch (Exception ex) { MessageBox.Show($"Error loading test data: {ex.Message}"); // Log the exception details for debugging if needed } finally { // Always close the connection when done if (con.State == ConnectionState.Open) con.Close(); } }
3. Additional Improvements
- Using Statements: For better resource management, wrap
SqlCommand,SqlDataAdapter, and even the connection inusingblocks to ensure they're disposed properly (prevents connection leaks). Example:using (SqlConnection con = new SqlConnection("your_connection_string")) using (SqlCommand cmd = new SqlCommand(query, con)) { // Your query logic here } - Strongly Typed Access: Instead of
dt.Rows[i].ItemArray[0].ToString(), usedt.Rows[i]["item_name"].ToString()—it's more readable and less error-prone if the query column order changes. - Randomization: I added the random pairing logic you mentioned in your comments using LINQ's
OrderBywith a random number generator. - Empty State Handling: The code now shows user-friendly messages and disables radio buttons when no data is found, preventing the original exception.
Why This Works
- Parameterized queries eliminate SQL injection risks and ensure the test name is passed correctly to the database, even if it has special characters.
- We explicitly check if the query returned rows and if the list has items before accessing
list[0], which stops the IndexOutOfRangeException. - Error handling catches any unexpected issues (like connection problems) and tells you exactly what went wrong.
内容的提问来源于stack exchange,提问作者Nils Erickson

