Does Console.Write ever fail? - c#

I am testing my run() function to make sure it has all the correct things populated by the end of the method. I populate 4 fields from our databases, two strings, and two IEnumerable(string)'s. The idea is to print them all out for all the people I am pulling from the database.
When I only print the string fields, everything works fine. However, when I try to add the Enumerables as well, nothing prints at all. I am also printing a counter so I know the program is still running and working. Does Console ever decide to not print anything at all due to space or something else?
Here's the code that does it:
int i = 0;
foreach (Contact contact in Contact.LoadWithPredicate(getAll))
{
-------other code to populate fields---------
i ++;
Console.WriteLine(i);
//Turn the Enumerables into strings for printing
string firstEnumAsString = String.Join(", ", firstEnumerable.ToArray());
string secondEnumAsString = String.Join(", ", secondEnumerable.ToArray());
Console.WriteLine("Email: " + firstString+ ", correspondance: " + secondString+ ", PAM addresses: " + firstEnumAsString+ ", famousPeople: " + secondEnumAsString);
}
So, as my output, whenever I run the code above, I get an output like this:
1
2
Email: foo#bar.com, correspondance: John, PAM addresses: bar#foo.com, famousPeople: foo, bar, foo
3
4
etc
Problem is, only two people out of the total (~425) show up, the rest of the lines are just numbers. Shouldn't I at least get the strings "Email", and ", correspondence"? It seems like Console is just deciding not to do anything. And I know that the code must reach it because it prints out the integer i just before I call that Console.WriteLine().
On the other hand, whenever I just ask for the two string fields to be printed, the Console displays both fields for all 425 users, right after their corresponding integer. Does anyone know what's happening here? TIA

Based on your comments, I think either your firstEnumerable or secondEnumerable objects are null. But since you did not post how you obtain these objects, I can't comment on why they are null or how to fix it.
It's okay for them to contain null entries, or even be fully empty, but they themselves cannot be null or it will throw an ArgumentNullException when you call .ToArray() on them. This corresponds with the "value cannot be null" exception message you're seeing.
The reason why it's not crashing and burning hard is because you are swallowing (and logging?) the exceptions within your iteration loop with a try/catch block that was not posted in your code sample.
I'm guessing your actual code is something like this:
foreach (Contact contact in Contact.LoadWithPredicate(getAll))
{
try
{
...
object[] firstEnumerable = null;
object[] secondEnumerable = null;
//some logic gates here which under some circumstances do not
//assign a valid instance to firstEnumerable or secondEnumerable
...
Console.WriteLine(i); //this prints every time
//Turn the Enumerables into strings for printing
string firstEnumAsString = String.Join(", ", firstEnumerable.ToArray()); //exception here
string secondEnumAsString = String.Join(", ", secondEnumerable.ToArray()); //or exception here
Console.WriteLine("Email: " + firstString+ ", correspondance: " + secondString+ ", PAM addresses: " + firstEnumAsString+ ", famousPeople: " + secondEnumAsString);
...
}
catch
{
//maybe some logging? maybe not?
}
}
This will print out the i value each time. But when it attempts to create firstEnumAsString or secondEnumAsString it throws an exception and never hits your second Console.WriteLine("Email: " + ...); thus producing the output you're seeing. It's not that the Console.WriteLine is failing, it's that you're never calling it in the first place.

If value is null, only the line terminator is written to the standard output stream.
For more information about the line terminator, see the Remarks section of the WriteLine() method. - Source
On top of that, if one of the values you're trying to write to the console throw an Exception, like in the following code:
private static string SomeVal { get { throw new Exception(); } }
Console.WriteLine("Foo");
Console.WriteLine("This throws an exception: " + SomeVal);
"This throws an exception:" won't be written to the console either; the entire string is just considered null. To me it looks like that's what's actually happening in your code; one of the values you're trying to write to the console is throwing an Exception, and it's handled somewhere silently. Are you running this code in a supressive try/catch clause?
You can easily figure out if that's the case by putting a breakpoint on Console.WriteLine or the trailing } and check the values of firstString, secondString and see if they're null. You can also tell whether one of the values you're trying to write threw an exception.
Also, you should consider using string.Format(string format, params object[] args) rather than concatenating with +. Makes debugging your code a lot easier, too.

Related

Unity and C# DebugLog Not Printing Everything

I'm working with Unity(+Vuforia), and I'm having some problems trying to print some variables that I want to identify the vuMark Augmented Reality Object (this a Vuforia thing) with, but I can't seem to get it to work.
My code is below, where I want the vuMarkID to be compared to "Table". In the DebugLog, however, my second statement (Debug.Log("vuMarkCompareToTable...")) returns 1. Even though the first statement (Debug.Log("ID = {0}"...)) returns "Table". I have tried trimming the vuMarkID string object, and also tried converting it directly, as you see below.
The other strange thing is nothing will print after "Table" in the debug log, for the first statement. I've tried concatenating using something like vuMarkID+"END", and the statement just cuts off at "Table". I've even tried printing using "ID = {0}{0}", and only the first "Table" prints. Even if the vuMarkID object changes (for instance, to Stool), it still does not print anything after the initial vuMarkID object.
How can I get the Debug.Log to recognize text after "Table" and have the CompareTo function return 0 when the arguments are (seemingly) the same?
Edit: I tried Debug.Log(string.Format("ID = " + vuMarkID + "DONE")); as well (I'm trying to see if there's something after the text), but that also cuts off immediately after the vuMarkID. I tried replacing for newline, just in case it was there, but it didn't have an effect.
//Gets the id of a VuMark Object
string vuMarkID = GetVuMarkId(vuMarkObj).ToString();
if (vuMarkID.CompareTo("Table ") == 0)
{
Debug.Log("Table found from tracking!");
}
else
{
string logdebug = vuMarkID;
object[] args = new object[] { (vuMarkID), vuMarkID.CompareTo("Table") };
Debug.Log(string.Format("ID = {0}", logdebug));
Debug.Log("vuMarkCompareToTable = " + (vuMarkID.Trim().CompareTo("Table")));
}
if (vuMarkID.CompareTo("Table ") == 0)
Note the " "(space) after Table.
If vuMarkID is "Table", it would go to else statement as it doesn't match.
You need to remove space:
if (vuMarkID.Trim().CompareTo("Table") == 0)
And to print object if its something else:
do this:
string vuMarkID = GetVuMarkId(vuMarkObj).ToString();
Debug.Log(vuMarkID); // this will always tell you id. No matter what it is.
if (vuMarkID.CompareTo("Table") == 0)
{
Debug.Log("Table found from tracking!");
// do table related stuff.
}
Hope this helps

Out of bounds exception whilst using arrays

I have an array of textboxes in which they change dyanmically depending on what the user types in. Those textboxes contain a number which represents a score of an assignment. Those score are linked to a module object. So if the user has 3 modules; 2 assignments on the first and second module and 3 assignments on the third module; then in total there would be 7 textboxes created for the user to input all their assignment marks.
What I am trying to do is to create a keyup event handler in which it gets the number in typed in by the user, and then dynamically calls a method to display the average of the the module. This is what I have so far. The following method gets called whenever the user types in a character:
public void calculateLevel4Modules(int counter) {
//iterate through modules
//iterate through assignts in that module
//whilst iterating, check tb and set userscore
//after iterating, update overall label with regards to modulecounter
//int assignmentCounter = 0;
//Console.WriteLine("in If statement.. " + counter);
for (int moduleCounter = 0; moduleCounter < requiredLevelList().Count; moduleCounter++)
{
int totalNumberOfAssignmentsInCurrentModule = requiredLevelList().ElementAt(moduleCounter).Assignments.Count;
Console.WriteLine("total number of assignmetns: " + totalNumberOfAssignmentsInCurrentModule);
assignmentCounter = assignmentCounter + totalNumberOfAssignmentsInCurrentModule;
Console.WriteLine("assignment counter: " + totalNumberOfAssignmentsInCurrentModule);
if (counter < assignmentCounter)
{
Console.WriteLine("in If statement.. " + userMarksTBLvl4[moduleCounter].Text);
try
{
int userMark = int.Parse(userMarksTBLvl4[counter].Text);
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
double modAvg = requiredLevelList().ElementAt(moduleCounter).getModuleScoreOverall();
moduleOverallLvl4[moduleCounter].Text = modAvg.ToString();
break;
}
catch (FormatException) { break; }
}
else { }
}
it works fine if the user has one module but if the user has two or more, then I get an error in the following line:
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
I am getting an out of bounds exception. I know why; its because counter is basically the # of the textbox that was typed into but by me using counter, I am accessing something not within the assignments list. This is an example of when the problem occus:
The user has 2 modules. In each module there are 2 assignments thus 4 textboxes are been created with their index ranging from 0 - 3. If the user wants to type in their score of the first assignment on the second module, its basically trying to write to the third index in that element then it crashes since that module only consist of 2 assignments.
There are some strange things in your code that make it hard to answer. First, the code you posted doesn't compile, so we have no way to test it.
Several times you use code like:
requiredLevelList().ElementAt(moduleCounter)
I assume requiredLevelList is a method that returns a list of things. There is no reason to assume requiredLevelList returns the same list, or even lists with the same number of elements, each time you call it. Maybe it does in your particular case, but this is a dangerous thing to rely on. You should use a construct like:
foreach (var module in requiredLevelList())
{
int totalNumberOfAssignmentsInCurrentModule = module.Assignments.Count;
...
module.Assignments.ElementAt(counter).UsersScore = userMark;
...
}
Code like this:
Console.WriteLine("total number of assignmetns: " + totalNumberOfAssignmentsInCurrentModule);
is symptomatic of trying to debug something after it has crashed. That is extremely inefficient. Learn how to use a debugger; you will not become an effective programmer until you know how to do this.
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
You're probably getting an out-of-bounds exception here because counter is outside the indexes of Assignments. Since you never initialize or change counter, I have no way to know what it is or should be. A debugger will tell you this, use one.
the # of the textbox that was typed into but by me using counter, I am accessing something not within the assignments list.
OK, if you're typing something “not within the assignments list” then you have to test for that and decide what to do. Perhaps something like:
if (counter >= 0 && counter < module.Assignments.Count)
module.Assignments.ElementAt(counter).UsersScore = userMark;
else
throw new Exception("I really have no idea what you want to do here.");
This also looks wrong:
moduleOverallLvl4[moduleCounter].Text = modAvg.ToString();
You never tell us what moduleOverallLvl4 is, but here you're assuming it has the same size as what is returned by requiredLevelList(). Maybe they are in this particular case, but that is a dangerous assumption. If these values are related, moduleOverallLvl4 should be contained in whatever class implements requiredLevelList, and you should have a method that assigns getModuleScoreOverall() to the correct element of moduleOverallLvl4.

Why did System.String[] appear as the output from printing 2d array?

Using this, I'm trying to print a list of the contents of players.text
I know that the foreach loop will print it just fine if the Console.Writeline
is used. But I'm attempting to manipulate the data in particular ways later, and need it split using the indicated delimiter.
However, with the given code all I get is a repeated System.String[] printout.
I've done a search or two and most of what I've found has to do with one part or the other, I haven't found any information on how to use them together.
string[] playerFile = File.ReadAllLines("players.txt");
foreach (string s in playerFile)
{
//Console.WriteLine(s);
string[] playerStuff = s.Split(';');
Console.WriteLine(playerStuff);
}
Console.ReadKey();
I realize it's a simplistic question. But often, for me at least, it's missing the obvious that drives me the most crazy.
Thanks in advance.
Player;Team;POS;HR;RBI;AVG
Abreu, J;CWS;1B;30;101;0.29
Altuve, J;HOU;2B;15;66;0.313
Andrus, E;TEX;SS;7;62;0.258
Arenado, N;COL;3B;42;130;0.287
Aybar, E;LAA;SS;3;44;0.27
The above is the first few lines of the input.
Basically, I want it to look just like that, minus the semicolons. Formatting will come later.
Attempting to add a second foreach, such as was suggested below, the code looked like this:
foreach (string s in playerFile)
{
//Console.WriteLine(s);
string[] playerStuff = s.Split(';');
foreach (string player in playerStuff)
{
Console.WriteLine(player);
}
}
This resulted in EACH piece of information getting it's own line. I follow the logic of why it did that, but I'm not sure what to do about it.
For a method call to compile the compiler has to figure out what you want to do and here, in particular, there are many overloads to the Console.WriteLine method. An "overload" basically means that there are several definitions of Console.WriteLine, all taking different types of parameters.
If the compiler can find an overload that takes exactly what you're trying to pass it, in this case string[], then good, that's the overload that will be called.
If not then it will take "the next best thing", if at all possible.
Let's list all the overloads to Console.WriteLine:
WriteLine()
WriteLine(Boolean)
WriteLine(Char)
WriteLine(Char[])
WriteLine(Char[], Int32, Int32)
WriteLine(Decimal)
WriteLine(Double)
WriteLine(Int32)
WriteLine(Int64)
WriteLine(Object)
WriteLine(Single)
WriteLine(String)
WriteLine(String, Object)
WriteLine(String, Object, Object)
WriteLine(String, Object, Object, Object)
WriteLine(String, Object, Object, Object, Object)
WriteLine(String, Object[])
WriteLine(UInt32)
WriteLine(UInt64)
Now, now of these will be able to accept a string[] except one:
WriteLine(Object)
This particular overload will simply call .ToString() on whatever it is passed.
Since a string array does not have a ToString implementation that looks at the contents of the array, or anything like that, the basic System.Object.ToString() method that every type inherits is used, and this simply returns the full name of the type as a string, which is basically System.String[].
So that's why the code compiles, and also why it doesn't do what you expect it to do.
The question is, what do you expect it to do?
If you wanted it to output all the strings as a comma-separated set of values on each line you can do this:
Console.WriteLine(string.Join(", ", playerStuff));
If you simply wanted to concatenate all the strings and put nothing between them, replace the ", " in the above statement with "" or string.Empty:
Console.WriteLine(string.Join(string.Empty, playerStuff));
The reason you are getting the output that you are is because it is trying to write the Array object to the console; and it doesn't know how to handle it, so it is just printing out the Type of the object that it is trying to write out.
You need to do another foreach or something similar on playerStuff.
string[] playerFile = File.ReadAllLines("players.txt");
foreach (string s in playerFile)
{
//Console.WriteLine(s);
string[] playerStuff = s.Split(';');
//Inner foreach that writes out each entry of the array
foreach(var item in playerStuff)
{
Console.Write(item + " ");
}
Console.Write(Environment.NewLine);
}
Console.ReadKey();
OR even simpler
string[] playerFile = File.ReadAllLines("players.txt");
foreach (string s in playerFile)
{
Console.WriteLine(s.Replace(';', ' '));
}
Console.ReadKey();
OR a one liner
string[] playerFile = File.ReadAllLines("players.txt");
playerFile.ForEach(x => Console.WriteLine(x.Replace(';', ' ')));
Console.ReadKey();
Sample output image for all 3 of the above solutions:
Console.WriteLine docs for reference
String.Replace docs for reference

Undo Operation fails on Repeated Use

I created an undo operation to set the current Value to the previous one that was within a list. It accomplishes this by removing the most recent index from the list and setting the value to the value that is behind it. Currently it works when there no value with in the list at initialization, as well as if there is more than one value within the list.
The code the way it is works when there is at least one index in the array, as previous unit tests pass this.
The problem is occurring where I try to have the InvalidOperationException to pass when the command is run twice, after the last item in the list has also been removed. so Add(5) -> Undo() -> Undo() to give an example. Also changing the if statement from valDict.Count > 0 to Value > 0, the same error occurs.
List<int> valDict = new List<int>();
public void Undo()
{
repOp1 = "Undo";
Console.WriteLine("1: " + valDict.Count);
if ( valDict.Count > 0)
{
int temp = valDict.Count - 1;
Console.WriteLine("2: " + temp);
valDict.RemoveAt(temp);
Console.WriteLine("3: " + valDict.Count);
valDict.TrimExcess();
//Below Line is flagged as the error
Value = valDict[valDict.Count-1];
}
else
{
throw new InvalidOperationException();
}
}
Can someone looking at this with fresh eyes, point out a possible solution, but not a fixed implementation, as I need to fix the implementation myself.
You can control that your List is not empty before getting the Value: list.Count==0, or !list.Any().

False positive using string.length in if statement

I'm trying to format phone numbers. Perhaps my approach is not the best but it works with the exception of some unexpected behavior. I'm using string.length in an if statement to see if the phone number's length (stored as a string) is greater than 9. I've also tried >= 10 instead of > 9 with the same results. All works fine with 18001234567 or 7041234567. I get (800) 123-4567 or (704) 123-4567. But with 828464047 I get (82) 846-4047 rather than the number just being returned as is.
try
{
if (ANI.Length > 9)
{
char[] Number1 = { '1' };
ANI = ANI.TrimStart(Number1);
return String.Format("{0:(###) ###-####}", Convert.ToDouble(ANI));
}
else if (ANI == "")
{
return "Private";
}
else
{
return ANI;
}
}
catch (Exception ex)
{
return ex.Message;
}
Any ideas? Is there a better way to approach this?
Thanks.
If I change the code that formats the phone number to use substrings, things break, as expected.
return "(" + ANI.Substring(0, 3) + ") " + ANI.Substring(3, 3) + "-" + ANI.Substring(6, 4);
An exception is caught and "Index and length must refer to a location within the string. Parameter name: length" is returned.
I put it into a unit test method and it works. You're obviously getting an extra character added onto the string 828464047. You can debug and place a breakpoint at the IF statement and see what is actually in ANI.
A few things as well,
Don't name a variable something ambiguous like "ANI".
rename Number1 to something like "firstNumber"
A try/Catch is not needed for this statement, if you're getting an exception you're doing something that can be solved by better coding.
I can see ANI.TrimStart() in your code which leads me to suspect that you have some leading whitespace. You can probably best solve the problem by moving the trimming to outside the if.
It's pretty safe to assume that something as fundamental as String.Length works correctly. When it says your string is a certain length, your string really will be that length.
I'd check your inputs for whitespace or, perhaps you transcribed your input wrong here. The following tests pass against your code, copied and pasted:
[TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
public void Ten_Digit_800_Number()
{
var myPad = new NumberFormatter();
Assert.AreEqual<string>("(800) 123-4567", myPad.FormatNumber("18001234567"));
}
[TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
public void Ten_Digit_800_Number()
{
var myPad = new NumberFormatter();
Assert.AreEqual<string>("(800) 123-4567", myPad.FormatNumber("18001234567 "));
}
[TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
public void TroubleString()
{
var myPad = new NumberFormatter();
Assert.AreEqual<string>("828464047", myPad.FormatNumber("828464047"));
}
The problem was stripping the leading '1' after having evaluated the length of the string. Stripping the '1' bef

Categories

Resources