|
I have two buttons (button1 and button2), a List<int> and a database. When form is loading, it selects a row from database with some values and assign them value to some labels and int variables. When I click on button1, the id of the row is inserted in list as an int value (idintrebare). In List can be maximum 26 elements. Here is my problem: when I click on button2, I want to select from database, rows where idintrebare is equal with id field from table (questions), but only one row per click, and assing to the same labels and int variables values from table. If all elements from list were selected, application will exit. Here is what I tried:
First I have the list:
List<int> coada = new List<int>(26);
Function for select data:
private void selectCoada()
{
using (Conexiune.getConnection())
{
foreach (int idi in coada)
{
string select = "SELECT DISTINCT * FROM questions WHERE id = '" + idi + "' LIMIT 1";
SQLiteCommand cmd = new SQLiteCommand(select, Conexiune.getConnection());
cmd.CommandType = CommandType.Text;
SQLiteDataReader rdra = cmd.ExecuteReader(CommandBehavior.CloseConnection);
try
{
while (rdra.Read())
{
textBox1.Text = rdra["question"].ToString();
textBox2.Text = rdra["answer1"].ToString();
textBox3.Text = rdra["answer2"].ToString();
textBox4.Text = rdra["answer3"].ToString();
r1 = (int)rdra["option1"];
r2 = (int)rdra["option2"];
r3 = (int)rdra["option3"];
idintrebare = Convert.ToInt32(rdra["id"]);
SimulatorManager.Intrebare = textBox1.Text;
}
}
catch (InvalidOperationException ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
In button1 I have just:
coada.add(idintrebare);
In button2 I have:
selectCoada();
The problem is that it selects only one value from list. I tried to use a for like this:
private void selectCoada()
{
using (Conexiune.getConnection())
{
for(int i=0;i<=coada.Count;i++) {
foreach (int idi in coada)
{
string select = "SELECT DISTINCT * FROM questions WHERE id = '" + idi + "' LIMIT 1";
SQLiteCommand cmd = new SQLiteCommand(select, Conexiune.getConnection());
cmd.CommandType = CommandType.Text;
SQLiteDataReader rdra = cmd.ExecuteReader(CommandBehavior.CloseConnection);
try
{
while (rdra.Read())
{
textBox1.Text = rdra["question"].ToString();
textBox2.Text = rdra["answer1"].ToString();
textBox3.Text = rdra["answer2"].ToString();
textBox4.Text = rdra["answer3"].ToString();
r1 = (int)rdra["option1"];
r2 = (int)rdra["option2"];
r3 = (int)rdra["option3"];
idintrebare = Convert.ToInt32(rdra["id"]);
SimulatorManager.Intrebare = textBox1.Text;
}
}
catch (InvalidOperationException ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
}
, but also didn't worked.
|
|
|
|
|
If you want to select one row each time button2 is clicked, and move through the rows in order:
private List<int> coada = new List<int>(26);
private currentIdi = 0;
if(coada.Count < 27) coada.add(idintrebare);
if(currentIdi == coada.Count || currentIdi == 25) Application.Exit;
currentIdi++;
selectCoada(coada[currentIdi]);
private void selectCoada(int idi)
{
using (Conexiune.getConnection())
{
string select = "SELECT DISTINCT * FROM questions WHERE id = '" + idi + "' LIMIT 1";
}
}
Comment: I think it's always a good idea to disable Controls when their use would cause an error, or when their use is irrelevant because the app is "not ready" to handle them. You might think about disabling 'button2 until clicking on it really can do something without an error.
«To kill an error's as good a service, sometimes better than, establishing new truth or fact.» Charles Darwin in "Prospero's Precepts"
|
|
|
|
|
I receive:
Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index
|
|
|
|
|
Code is good, but when all item have been passed and should show finish message, I receive that
|
|
|
|
|
It's ok, I fixed it. Thank you very much for your help, I understand now
|
|
|
|
|
Good
«To kill an error's as good a service, sometimes better than, establishing new truth or fact.» Charles Darwin in "Prospero's Precepts"
|
|
|
|
|
Unfortunately, I still have a problem. I thought I fixed it, but I was wrong. I understand why I receive that, but I don't know how to fix it. Can you help me with that?
|
|
|
|
|
If the problem you have now is a totally new kind of problem you haven't mentioned before, then I suggest you start a new question and include code samples, error messages, etc.
If it's the same problem you've discussed already, I suggest you add a new post to this thread and describe exactly what's not working the way you expect.
Have you stepped through your code with the debugger and isolated where the problem occurs ?
«To kill an error's as good a service, sometimes better than, establishing new truth or fact.» Charles Darwin in "Prospero's Precepts"
|
|
|
|
|
Aaaa sorry, I thought you might know what problem can appear in that case. Well, On button2, you know that I call select function. Well, after last id was selected from list, I receive that error message about index. That means that the list is empty and currentIdi can't have a negative value.
modified 5-Apr-15 9:36am.
|
|
|
|
|
Put a breakpoint in your code, and when you hit the breakpoint, use F11 to single-step through the code, observe where the error occurs.
Analyze what happened that caused the error, and then fix your code.
I think you have everything you need to get this fixed.
«To kill an error's as good a service, sometimes better than, establishing new truth or fact.» Charles Darwin in "Prospero's Precepts"
|
|
|
|
|
I solved it. Sorry and thank you for your time
|
|
|
|
|
Your code is vulnerable to SQL Injection[^].
NEVER use string concatenation to build a SQL query. ALWAYS use a parameterized query.
string select = "SELECT DISTINCT * FROM questions WHERE id = @id LIMIT 1";
SQLiteCommand cmd = new SQLiteCommand(select, Conexiune.getConnection());
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("@id", idi);
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
|
I have a new file every few seconds that looks like this: 23 45 21 1 9 23 42 22 40 11 33 32 18 11 12 32 22 7 37 30 in this text file to be read there is one number per line that will be between 1-40. these files are generated several times a minute. I am trying to order them ascending with stringreader and writer. my logic must be flawed as nothing shows up in this file i intended to send it to, i selected append= true but still nothing is populated in my sorted file. the goal was to read from the text file with the for loop which contains 1-40 int variables and compare that to each string or int from the file read and when found copy that from the read file into the sorted file in sorted order,I have been looking at it for a while and it should work but does not please help i have hit a brick wall and don't see why it does not work. would this be easier with the file reader/writer classes or streamreader/writer as i have done,thanks
public static void ProcessDirectory()
{
int variable1;
StreamReader readToSort = new StreamReader(@"C:write.txt");
StreamWriter writeSorted = new StreamWriter(@"C:Sorted_File.txt", true);
for (int i = 1; i > 41; i++)
{
variable1 = (readToSort.Read());
while (!readToSort.EndOfStream)
{
if (variable1 == i)
{
writeSorted.Write(i.ToString() + "\n");
}
}
MessageBox.Show("processing #" + variable1);
}
readToSort.Close();
writeSorted.Close();
}
modified 4-Apr-15 14:02pm.
|
|
|
|
|
|
sorry my bad not intentional
|
|
|
|
|
Assume you have a Class named 'TheClass : here's what you might call a 'normal' ctor:
public class TheClass
{
public string Name { private set; get; }
public List<int> TheClassList { private set; get; }
public TheClass(string name, int init, int inc, int last)
{
Name = name;
TheClassList = new List<int>;
for (int i = init; i < last; i+= inc)
{
TheClassList.Add(i);
}
}
} Now you decide that you want to give the user the option to inject a function into ctor that will modify the generation of values in the 'for loop: so you write a Function:
public Func<int, int> Generator1 = (value) => (value * value); And, you modify the class to pass the Function as a parameter to the ctor, and use it:
public class TheClass
{
public string Name { private set; get; }
public List<int> TheClassList { private set; get; }
public TheClass(string name, int init, int inc, int last, Func<int,int> Generator = null)
{
Name = name;
TheClassList = new List<int>;
if(Generator == null)
{
for (int i = init; i < last; i+= inc)
{
TheClassList.Add(i);
}
}
else
{
for (int i = init; i < last; i+= inc)
{
TheClassList.Add(Generator(i));
}
}
}
} All this is, imho, passable; my question regards what happens when you have many optional types of Functions (or Actions) that you want to be used in the ctor ... so that if you made all of those Funcs (or Actions) part of the ctor parameter list (with 'null as their default value) you'd get a very unwieldy ctor, and/or complex logic in the ctor to decide which functions passed as parameters are invoked.
Here's what I see as the alternatives:
I. define a separate ctor for each possible use case (my current choice).
public TheClass(string name, int init, int inc, int last);
public TheClass(string name, int init, int inc, int last, Func<int,int> Generator1);
public TheClass(string name, int init, int inc, int last, Func<int,int,int, List<int>> Generator2);
II. break-out the code in the ctor in two parts: one that handles everything but the generation of values; put the code for all possible value generation scenarios (and its logic) into a separate 'Initialize function that must be called after the call to the ctor.
III. define the most common (default) initialization method in the ctor, and pass a boolean flag as a parameter to the ctor: if the flag is true, initialization is performed in the ctor, else defer initialization to a call to an 'Initialize function.
Appreciate your thoughts !
«To kill an error's as good a service, sometimes better than, establishing new truth or fact.» Charles Darwin in "Prospero's Precepts"
modified 4-Apr-15 12:58pm.
|
|
|
|
|
Of those, I prefer 1, but they all do too much; a constructor should do very little.
Better to have the constructor receive the List rather than build it. If you do, you might want to make a copy.
A benefit of this technique is that it allows the caller to instantiate your class multiple times with the same data without generating it more than once.
And consider using params :
public TheClass(string name, params int[] List)
{
Name = name;
TheClassList = new List<int> { List };
The caller can use this with the values he wants:
TheClass a = new TheClass ( "A" , 1 , 2 , 3 ) ;
int[] l = new int[] { 1 , 2 , 3 } ;
TheClass b = new TheClass ( "B" , l ) ;
Basically, generating the list is not the constructor's concern.
Having said that... I'm reminded of a Pool<T> class I wrote. Its constructor takes a delegate that constructs one item for the pool and the number of items it should manage. Maybe I should change it to follow my advice above.
[System.ObsoleteAttribute("Don't use this constructor",true)]
public Pool
(
int Capacity
,
Delegate Creator
)
{
this.pool = new T[Capacity];
for (int i = 0; i < this.pool.Length; i++)
{
this.pool[i] = Creator();
}
return;
}
public Pool
(
params T[] Pool
)
{
this.pool = Pool;
return;
}
Modularity, single-responsibility, etc.
modified 4-Apr-15 13:10pm.
|
|
|
|
|
Hi, I appreciate your comments.
For the sake of focusing on what I think is the key issue ... handling the need to have a constructor with a variable number of parameters some of which may be Action or Func ... which are used dynamically in the ctor ... the code I showed here is deliberately as terse and simple as possible.
In the real-world code I am working with (complex, involving Types other than int) the constructors in the library I am creating do need to trigger the construction of lists ... it's a key part of the class' functionality to provide the lists.
It's a personal preference of mine to avoid using 'params unless required, since I feel the use of named variables always contributes to code maintainability; but, of course, you're right in that they are sometimes absolutely necessary because you are dealing with an unpredictably variable number of inputs at run-time. So, I do use them; in fact, I use them in the current library I'm working on.
Your code example is interesting: I don't see you passing the 'i for-loop indexer to the Delegate, which seems strange. The use of 'Delegate there would require you to define a prototype for the Delegate Type like: public delegate T IntDelegate(); to use in the 'ctor.
On the other hand using a Func<T> would require no extra declaration, and, since Func is a Delegate, would be entirely equivalent.
cheers, Bill
«To kill an error's as good a service, sometimes better than, establishing new truth or fact.» Charles Darwin in "Prospero's Precepts"
|
|
|
|
|
BillWoodruff wrote: it's a key part of the class' functionality to provide the lists
That sounds suspicious.
BillWoodruff wrote: you to define a prototype for the Delegate Type
Yes, because I'm old-school, I try not to use new crap when the old crap still works just fine. I just didn't show it.
modified 4-Apr-15 14:36pm.
|
|
|
|
|
If you have a List of Actions to perform, then why are we talking about constructors? Why are you passing in an action, if you can pass an interface?
I'd also like to point out a recent thread[^] on the readability of the constructor
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
Hi,
I did, indeed, read the thread you refer to in the Lounge, with interest. In fact, my choice to implement multiple constructors ... what I consider best practice now ... one for each case ... is based on believing that improves code maintainability, and readability.
But, I did start this thread with the thought I might learn something new, and I'm certainly willing to change my current preferences
As I just posted to Piebald on this thread: "For the sake of focusing on what I think is the key issue ... handling the need to have a constructor with a variable number of parameters some of which may be Action or Func ... which are used dynamically in the ctor ... the code I showed here [in the original post on this thread] is deliberately as terse and simple as possible."
I can't grok what you are referring to when you say: "pass an interface;" and, I'm curious, how would that work ?
thanks, Bill
«To kill an error's as good a service, sometimes better than, establishing new truth or fact.» Charles Darwin in "Prospero's Precepts"
modified 4-Apr-15 15:09pm.
|
|
|
|
|
BillWoodruff wrote: believing that improves code maintainability, and readability.
I'm with you on that.
|
|
|
|
|
BillWoodruff wrote: I can't grok what you are referring to when you say: "pass an interface;" and,
I'm curious, how would that work ? You can't bind an interface to an action obvious. But if you can pass an Action<T> or Func<T>, then you can pass an object that implements a specific interface. It may require a bit more code, but the advantage of passing merely an interface appears obvious.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
Hi, Eddy,
I believe I see the point you are making, and I certainly agree with you that passing an instance of #Whatever as an IWhatever is a good way to minimize what "parts" of an instance you expose. I can, and do, use interfaces that spec Funcs; example:
public interface IGenericWhatever<T> where T : struct
{
Func<T, T> SomeFunc1 { set; get; }
Func<T, T, T, List<T>> SomeFunc2 { set; get; }
} For the particular "library for programmers" use case I am developing now, I find it appropriate for the programmer to pass Func definitions in the call to the Class' ctor.
When (if) I publish this library on CP, I'll ask for your review.
thanks, Bill
«To kill an error's as good a service, sometimes better than, establishing new truth or fact.» Charles Darwin in "Prospero's Precepts"
|
|
|
|
|