c# I have a very confusing InvalidCastException error - c#

I'm having an error that says "invalid cast exception" whenever I try to open one specific form in a program i'm making. The code here takes data from text files to put it into a data grid view. It also makes calculations to put averages in the data grid view. I'm getting an error that seems to involve a variable called "skiTime", which is an average of 3 other variables: "skiTime1" "skiTime2" and "skiTime3". The numbers are decimals, e.g. 23.22, or 54.32, etc.
When I try to load this form, the program closes and Visual studio highlights this line:
decimal skiTimeDecimal = Convert.ToDecimal(skiTime[i]);
I don't know what part of the code the error is in, it could literally be anywhere since my code is so messy, I basically just pulled from random tutorials, and answers to questions I asked here because I need it done for school and don't know c#. Here's the full part of the code that I think might relate to this error.
using (StreamWriter sw = new StreamWriter("groups.txt", false))
{
for (int i = 0; i < skiTimeID.Count; i++)
{
for (int j = 0; j < quizID.Count; j++)
{
for (int l = 0; l < pupilDetailsID.Count; l++)
{
if (skiTimeID[i] == quizID[j] && quizID[j] == pupilDetailsID[l])
{
string fullPupilRecord = pupilDetailsID[l] + "~" + pupilDetailsFirstName[l] + "~" + pupilDetailsSurname[l] + "~" + pupilDetailsClass[l]
+ "~" + pupilDetailsNumber[l] + "~" + skiTime[i] + "~" + quizScore[j] + "~" + quizPercentage[j];
int quizScoreNumber = Convert.ToInt32(quizScore[j]);
decimal skiTimeDecimal = Convert.ToDecimal(skiTime[i]);
if (quizScoreNumber >= 3 && skiTimeDecimal <= 40)
{
groupLevel = "Advanced";
}
else if (quizScoreNumber >= 2 && skiTimeDecimal <= 50)
{
groupLevel = "Intermediate";
}
else
{
groupLevel = "Beginner";
}
fullPupilRecord = fullPupilRecord + "~" + groupLevel;
sw.WriteLine(fullPupilRecord);
fullPupilRecord = "";
}
}
}
}
If it helps, here is the code that finds the average between the variables for skiTime:
public string CalculateAverage(List<string> skiTime1, List<string> skiTime2, List<string> skiTime3)
{
List<string> allValues = new List<string>();
allValues.AddRange(skiTime1);
allValues.AddRange(skiTime2);
allValues.AddRange(skiTime3);
decimal totalcount = 0;
decimal average = 0;
foreach (var value in allValues)
{
totalcount = totalcount + decimal.Parse(value);
}
average = totalcount / allValues.Count();
return average.ToString();
}

Related

How can I write a loop to set the value of sum[i] and delete datatable columns where sum[i] <= 0

int i = 0;
string[] sum = new string[256];
for (i = 1; i < 256; i++)
{
sum[i] = sum[i].ToString();
sum[i] = Convert.ToInt32(dt.Compute("Sum(BIN" + i.ToString() + ")", string.Empty));
if(sum[i] == 0)
{
dt.Columns.Remove("BIN"+i.ToString()+"");
}
}
There is a problem where you're trying to assign an int to sum[i], because sum is a string[], and you can't assign an int to one of the items.
Instead, it seems you want to get the return value from the method and save it in a variable so you can compare it. In order to do this, we can modify the code like:
string[] sum = new string[256];
for (int i = 1; i < 256; i++)
{
int result = Convert.ToInt32(dt.Compute("Sum(BIN" + i.ToString() + ")", string.Empty));
if (result <= 0)
{
dt.Columns.Remove("BIN" + i.ToString() + "");
}
}
This can be simplified further by using the return value of the method directly in the if condition. We can also use interpolated strings instead of concatenation:
string[] sum = new string[256];
for (i = 1; i < sum.Length; i++)
{
if(Convert.ToInt32(dt.Compute($"Sum(BIN{i})", string.Empty)) <= 0)
{
dt.Columns.Remove($"BIN{i}");
}
}

Look and say sequence

I'm trying to make a look and say sequence ant my code so far only works as it should when I have the 'realCounter' set to 2 or less and don't understand why. Thanks for any help! Here is my main :
string number = "1";
string[] tempStore = new string[2];
int realCounter = 0;
while (realCounter < 2)
{
int counter = 1;
for (int i = 0; i < number.Length; i++)
{
try
{
if (number[i] == number[i + 1])
{
counter++;
}
}
catch
{
tempStore[0] = number[i].ToString();
number = counter.ToString();
number = number + tempStore[0];
}
}
realCounter++;
}
Console.WriteLine(number);
Console.ReadLine();
I've been changing the line with the while loop from realCounter < 2 to realCounter < 3 and the program doesn't perform as it should
It is because you are specifically checking to ensure realCounter < 2 as a condition of your while loop
try
{
if (number[i] == number[i + 1])
{
counter++;
}
}
catch
{
tempStore[0] = number[i].ToString();
number = counter.ToString();
number = number + tempStore[0];
}
You are only updating your number variable when you encounter an exception. You only encounter an exception when number[i + 1] hits an IndexOutOfBounds exception. So you're only updating number with the LAST sequence it encounters, and you're dropping all the rest.

How to get all rows in two foreach?

I don't know how to get the first rows of a first foreach run with the first rows of a second foreach.
The second rows of a first foreach run with the second rows of the second foreach.
Because I get all data into List<> and the foreach two list.
My code like:
for (int i = valuesFrom; i < valuesTo; i++)
{
values = name + " " + i;
lstAliasImage.Add(values);
}
for (int j = 0; j < lstImgAdded.Items.Count; j++)
{
string imgPath = lstImgAdded.Items[j].Text;
lstNameImage.Add(imgPath);
}
foreach (var alias in lstAliasImage)
{
foreach (var items in lstNameImage)
{
txtUser.Text = alisa;
Save(items + " " + txtUser.Text);
}
}
You can do that with a good old for cycle:
for (int i = 0; i < lstAliasImage.Count; i++) {
txtUser.Text = listAliasImage.ElementAt(i);
Save(lstNameImage.ElementAt(i) + " " + txtUser.Text);
}
Here I assumed that by alisa you meant alias. Also, I assumed that the element count is the same. If your type has an indexer defined, then you can use [i] instead of ElementAt(i).
Using a for loop will solve your problem;
for (int i = 0; i < lstAliasImage.Count; i++)
{
txtUser.Text = lstAliasImage[i];
Save(lstNameImage[i] + " " + txtUser.Text);
}
But it is better to solve this in a different way. As both Lists are related, you should create a struct, and store that in the list. At least to avoid errors if both lists are not the same length. Something like
public struct ImageStruct
{
public String alias;
public String name;
}
List<ImageStruct> images = new List<ImageStruct>();
for (int i = valuesFrom; i < valuesTo; i++)
{
images.Add(new ImageStruct()
{
alias="alias " + i,
name="name " + i
});
}
foreach (var item in images)
{
txtUser.Text = item.alias;
Save(item.name + " " + item.alias);
}
I hope you get the idea (I did not test the above code).

How can I remove the values apostrophes of my choice from a line?

I want to remove in each line from specific values the apostrophes.
This is my code for writing into a text file:
for (int a = 0; a < checkedListBox1.CheckedItems.Count; a++)
{
DataTable ExportTable = new DataTable();
//Debug.WriteLine(checkedListBox1.CheckedItems[a].ToString());
string SelectLines =
"SELECT Identifier,
TestID,
Description,
Enabled,
StringLimit,
LowLimit,
HighLimit,
LimitType,
Unit,
Parameters
FROM specifications
where Identifier = '" + checkedListBox1.CheckedItems[a] + "'";
ExportTable = ObjSqlAccess.GetDataTableFromTable(SelectLines);
int rowcount = ExportTable.Rows.Count;
int columncount = ExportTable.Columns.Count;
int rw = 0;
int clm = 0;
writeText.WriteLine("\r\n\r\n[" + checkedListBox1.CheckedItems[a].ToString() + "]" + "\r\nCount = " + (rowcount - 1));
for (rw = 0; rw < rowcount - 1; rw++)
{
string test = "";
for (clm = 0; clm < columncount - 1; clm++)
{
test += ExportTable.Rows[rw][clm].ToString();
test += "','";
}
writeText.WriteLine((rw + 1) + "=(Identifier,TestID,Description,Enabled,StringLimit,LowLimit,HighLimit,LimitType,Unit,Parameters) VALUES ('" + removeThis + "')");
}
writeText.Flush();
writeText.Close();
writeText.Dispose();
And for instance, I want to remove the apostrophes from each line from only these values: 1, 0 , 0 before writing it to a text file. Or to be more specific, only the values that are assigned to Enable, LowLimit and HighLimit column.
Does anyone has an idea of how to proceed? I hope my question is clear enough.
Try this:
for (clm = 0; clm < columncount - 1; clm++)
{
DataColumn col = ExportTable.Columns[clm];
test += ExportTable.Rows[rw][clm].ToString();
if (col.DataType == bool || col.DataType == Int32) //Add other types that dont require single quotes to if statement
{
test += ",";
}
else
{
test += "','";
}
}
First, I would change the way you're writing the string so it doesn't care if there are single quotes, or anything else, in the variable you pass for VALUES.
writeText.WriteLine((rw + 1) + "=(Identifier,TestID,Description,Enabled,StringLimit,LowLimit,HighLimit,LimitType,Unit,Parameters) VALUES (" + test + ")");
Also worth noting is I don't think your loops will work correctly. When you use a count in a for loop, the count is already 1-indexed. So, if you do columnCount = ExportTable.Columns.Count;, your loop should be for (int i = 0; i < columnCount; i++). An easy way to remember is index is 0-based, but count is 1-based.
I would also use a string builder instead. Then in your loop just do a check for those columns:
string test = "";
for (clm = 0; clm < columncount; clm++)
{
StringBuilder sb = new Stringbuilder();
sb.Append(ExportTable.Rows[rw][clm].ToString());
if (clm != 3 && clm != 5 && clm != 6)
{
sb.Insert(0,"'");
sb.Append("'");
}
test += sb;
if (clm != columncount - 1) // add a comma if it's not the last column
{
test += ",";
}
}

ArgumentOutOfRange exception C#

I am doing my homework and I have to do a program that extends simple letters from a file, like E and F, to continuous productions, given also in the folder, such as E+T E-F etc. Anyway the code shown below gives me an argument out of range exception. I crafted the same code in java and all works fine. I don't know why in C# it gives me this exception. Please give me some advice!!
I forgot to put the file that I'm reading from:
EFT
a+()
E
E+T|E-T|T
T*F|T/F|F
a|(E)
public void generare(){
String N = null;
String T = null;
String S = null;
String[] P = null;
TextReader tr = new StreamReader("dateIntrare.txt");
try
{
N = tr.ReadLine();
T = tr.ReadLine();
S = tr.ReadLine();
P = new String[N.Length];
for (int i = 0; i < N.Length; i++)
{
P[i] = tr.ReadLine();
}
tr.Close();
Console.WriteLine("Neterminale: N = " + N);
Console.WriteLine("Terminale: T = " + T);
Console.WriteLine("Productii ");
for (int i = 0; i < P.Length; i++)
Console.WriteLine("\t" + P[i]);
Console.WriteLine("Start: S = " + S);
Boolean gata = false;
String iesire = S.Substring(0, S.Length);
Console.WriteLine("\nRezultat");
Console.Write("\t");
while ((gata == false) && (iesire.Length < 50))
{
Console.Write(iesire);
Boolean ok = false;
for (int i = iesire.Length - 1; i >= 0 && ok == false; i--)
{
for (int j = 0; j < N.Length && ok == false; j++)
if (N[j] == iesire[i])
{
String s1 = iesire.Substring(0, i);
String s2 = iesire.Substring(i + 1, iesire.Length); // HERE IS THE EXCEPTION TAKING PLACE
String inlocuire = P[N.IndexOf(iesire[i])];
String[] optiuni = null;
String[] st = inlocuire.Split('|');
int k = 0;
foreach (String now in st)
{
k++;
}
optiuni = new String[k];
st = inlocuire.Split('|');
k = 0;
foreach (string next in st)
{
optiuni[k++] = next;
}
Random rand = new Random();
int randNr = rand.Next(optiuni.Length);
String inlocuireRandom = optiuni[randNr];
iesire = s1 + inlocuireRandom + s2;
ok = true;
}
}
if (ok == false)
{
gata = true;
}
else
{
if (iesire.Length < 50)
Console.Write(" => ");
}
}
}
catch (FileNotFoundException)
{
Console.WriteLine("Eroare, fisierul nu exista!");
}
Console.WriteLine();
}
But why in java works and here not? I'm confused
When in doubt, read the documentation. In Java, the 2-parameter overload of substring takes a start index and an end index. In .NET, the second parameter is the number of characters to take, not an end index.
So you probably want
String s2 = iesire.Substring(i + 1, iesire.Length - i - 1);
Or to be simpler about it, just use the 1-parameter version, which takes all the characters from the specified index onwards:
String s2 = iesire.Substring(i + 1);
(I'd use that in Java too...)
Fundamentally though, it's worth taking a step back and working out why you couldn't work this out for yourself... even if you missed it before:
Look at the line that threw the exception in your code
Look at which method actually threw the exception (String.Substring in this case)
Look at the exception message carefully (it's a really good hint!) and also any nested exceptins
Read the documentation for the relevant method carefully, especially the sections describing the parameters and exceptions
This is a common mistake while porting codes from Java to c#.
Substring in Java takes start & end parameters but in c# they are start and length

Categories

Resources