I'm doing an activity that asks your name, and if a number is inserted it should tell that the input is invalid.
Here's my code:
try {
Console.Write("Enter your first name: ");
string fname = Console.ReadLine();
Console.Write("You're Name is: " + fname);
}
catch (Exception) {
Console.Write("INVALID NAME");
}
Sample output:
Enter you're first name: 123hjay
INVALID NAME!!
I know my exception is wrong; I need your help guys.
You seem to have misunderstood the purpose of exceptions.
Exceptions are thrown when a program encounters an error in its execution. For example assigning a letter to an int would throw an error. While opinions vary, I tend not to handle user input errors with exceptions. Furthermore, think about the logic you wrote in your code. How could the program know that entering numbers into a variable named fname is incorrect?
Write in logic into your program to test for input errors and then return an appropriate response. In your case, if you wanted to ensure that there were no numbers entered, you could do the following:
if (name.Any(char.IsNumber))
{
Console.WriteLine("Invalid Name.");
}
Console.ReadLine();
As my comment says (in the question), I didn't really get what it is you are asking, because it doesn't throw anything, but if you did want it to throw an error (also suggested by the comments), this should help:
Console.Write("Enter you're first name: ");
string fname = Console.ReadLine();
foreach (var character in fname)
{
if (Char.IsDigit(character))
throw new Exception("Numbers are not allowed.");
}
Console.Write("You're Name is: " + fname);
It's very straight forward and you can read it as English and understand what I've done.
You can mess around with the code, look at similar functions with Visual Studios IntelliSense and tweak it to your needs.
If you need, add a try & catch blocks, of course.
for the courtesy of replying back, here is the answer.
Hint: your exception is right!
Enter in your console "Glee" it will not throw exception.
If you type "7337" it does throw exception.
try to use : fname.ToString();
Related
Let me start off saying that I'm new to C#.
I'm currently in the making of my first command-line application that in it's current state can do two things. One of them is a calculator, for which I need more learning to actually make it work, and the other is a string capitalizer.
I have a string nameCapInput = Console.Readline() that takes in the user input, which then gets analyzed to make sure that no digits are allowed:
using System;
using System.Linq;
namespace First_Console_Project
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("My first ever console application - 2020/2/26\n\n\n");
programSel:
Console.WriteLine("What do you want to do?\n");
Console.WriteLine("1. Calculate Numbers \n2. Capitalize Letters/Strings");
Console.WriteLine("Input your desired action:");
var inputVar = Console.ReadLine();
switch (inputVar)
{
case "1":
//Calculator code goes here
Console.WriteLine("Number 1 succeeded, opening calculator... Stand by");
Console.WriteLine("Calulator Loaded.");
Console.WriteLine("Doesn't work right now. Type \"exit\" to get back to the \"what do you want to do\" page.");
//Code goes here when I have learned the proper methods
calcInput:
var calcInput = Console.ReadLine();
if (calcInput == "exit")
{
goto programSel;
} else
{
Console.WriteLine("Unknown command. Type \"exit\" to get back to the \"what do you want to do\" page.");
goto calcInput;
}
case "2":
Console.WriteLine("Loading string capitalizer...");
Console.WriteLine("Type any string made of letters only without spaces, because if you use spaces, the program will exit. The output will make them all uppercase. Type \"exit\" to get back to the \"what do you want to do\" page.");
inputCap:
string nameCapInput = Console.ReadLine();
bool containsInt = nameCapInput.Any(char.IsDigit);
bool isMadeOfLettersOnly = nameCapInput.All(char.IsLetter);
if (nameCapInput == "exit")
{
goto programSel;
}
else if (containsInt)
{
Console.WriteLine("You can't capitalize numbers. Use letters only. Try again.");
goto inputCap;
}
else if (isMadeOfLettersOnly)
{
string upper = nameCapInput.ToUpper();
Console.WriteLine($"The uppercase version of your entered text is: {upper}");
goto inputCap;
}
break;
}
}
}
}
Now, everything works fine and it capializes everything I put into it except strings with spaces in them. When I type in a string with spaces in it, the program just exits with code 0. I'm not very good at C# yet, so I don't really know where to go from here. Any help is appreciated.
Every time I learn something new in C#, I try to implement it into my projects, so I can actually learn how to implement it to know when and how to use what I learned. This is an example for that.
EDIT: Added the rest of the code.
Thank you all very much. There's two things I have learned here:
goto is a bad habit
I absolutely need to start learning to debug my own code.
The crux of your problem is that you are only checking if the input contains letters (not spaces). An easy fix is to change your LINQ a bit.
bool isMadeOfLettersOnly = nameCapInput.All(c => char.IsLetter(c) || char.IsWhiteSpace(c));
So now input with letters or spaces will be considered valid.
In addition, your use of goto is a very bad idea. Generally there should never be any reason to use goto.
To fix this, use a while loop and a method:
public static void Main()
{
bool exit = false;
do {
exit = ProcessInput();
}
while(!exit);
}
private static bool ProcessInput()
{
string nameCapInput = Console.ReadLine();
bool containsInt = nameCapInput.Any(char.IsDigit);
bool isMadeOfLettersOnly = nameCapInput.All(c => char.IsLetter(c) || char.IsWhiteSpace(c));
if (nameCapInput.Equals("exit", StringComparison.CurrentCultureIgnoreCase))
{
return true; //exiting so return true
}
else if (containsInt)
{
Console.WriteLine("You can't capitalize numbers. Use letters only. Try again.");
}
else if (isMadeOfLettersOnly)
{
string upper = nameCapInput.ToUpper();
Console.WriteLine("The uppercase version of your entered text is: {0}", upper);
}
return false; //no exit, so return false
}
This is just a quick refactor, you could make it better.
Fiddle here
Check the documentation: https://learn.microsoft.com/en-us/dotnet/api/system.char.isletter?view=netframework-4.8
Based on the documentation of the IsLetter function, the space is not included in the return true cases.
I would suggest that you use regular expressions for this or change your last case to
else if (!containsInt)
{
var upper = nameCapInput.ToUpper();
Console.WriteLine($"The uppercase version of your entered text is: {upper}");
goto inputCap;
}
Also check the documentation of goto: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto
The goto statement transfers the program control directly to a labeled statement.
A common use of goto is to transfer control to a specific switch-case label or the default label in a switch statement.
The goto statement is also useful to get out of deeply nested loops.
You are not in any such case, so you shouldn't use it.
I'm trying to the catch System.ArgumentException "The URL cannot be empty." and display a message:
catch (System.ArgumentException errormsg)
{
string errorVar = Convert.ToString(errormsg);
if (errorVar == "System.ArgumentException: The URL cannot be empty.")
{
MessageBox.Show("The URL / Filename cannot be empty. Please check and try again");
}
else
{
MessageBox.Show("There is no message for this error:- " + errorVar);
}
}
At the moment, it keeps running the "Else" scenario with the message box of :
NB: line 153 = doc.Load(openFileDialog1.FileName);
Could someone please help me get it running the "if" instead of the "else" ?
Instead of trying to parse the exception, you should be looking at what causes it. In this case, the problem is that openFileDialog1.FileName is empty, so, what you should be doing is something like this:
try
{
if (string.IsNullOrEmpty(openFileDialog1.FileName))
{
MessageBox.Show("You need to select the file to open");
}
else
{
// Only attempt to do this if you know the user selected some value
doc.Load(openFileDialog1.FileName);
}
}
catch (ArgumentException ex)
{
//Show some error that is not caused by the URL being empty
}
As a general rule, you need to validate user input before attempting to use it.
string errorVar = errormsg.Message; //this would give you the error message
then you can compare it
if (errorVar.Equals("The URL cannot be empty."))
you can also use .Contains or .StartsWith
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am not sure how to get the exceptions to work
the program should prompt for the whole number of pounds to convert and the exchange rate. It then should display the equvlient number of follars in a manner similar to the output below.
the first part works here is my code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CurrencyConvertor
{
class Program
{
static void Main(string[] args)
{
CurrencyConvertor();
Console.ReadLine();
}
private static void CurrencyConvertor()
{
int ivalue;
float exchange;
float results;
bool valid;
Console.WriteLine(" please enter a whole number of pounds");
do
{
try
{
ivalue = int.Parse(Console.ReadLine());
Console.WriteLine(" pounds entered : " + ivalue);
Console.WriteLine("please enter the exchange rate");
exchange = float.Parse(Console.ReadLine());
Console.WriteLine(" exchange rate is " + exchange);
results = ivalue * exchange;
Console.WriteLine(" £ " + ivalue + " is equivlent to" + " $ {0:N}", results);
valid = true;
}
catch
{
Console.WriteLine("unable to convert to integer");
Console.WriteLine(" Try again- ensure you enter a number");
valid = false;
}
} while (valid == false);
Console.ReadLine();
}
}
}
Both inputs should be validated to ensure that the user enters an appropriate data type - the output below illustrates the expected output if the user enters non numerical data.
so it should displays
please enter an integer
try again - ensure you enter an integer
12
pounds entered 12
please enter an exchange rate
asd
unable to convert to a number
try again - ensure you enter a number
1.56
exchange rate is 1:56
£12.00 is equivalent to $18.72
I cant seem to get it to display the error message for the exchange rate to say " unable to convert to a number "
There are some flaws in your code:
you should prefer int.TryParse instead of Parse. An Exception should be an unexpected behavior, where you have to react in some way. A userinput is not unexpected, you know there's a chance that the use inputs invalid data which you can/have to validate.
When you use exceptions, you should not catch all exceptions at once, but some type of exception where you know how to react. int.Parse itself throws three kind of exceptions (see http://msdn.microsoft.com/de-de/library/b3h1hf19(v=vs.110).aspx), you can get some other ones from the system itself. Your code should catch FormatException instead of a catch-all.
anyway, if you just want to fix your code, you can solve your problem with using two seperate try .. catch blocks with seperated error messages.
Exceptions are there to catch the exceptional - the things you don't expect to happen but might
You should be using TryParse methods instead
while(!int.TryParse(Console.ReadLine(), out ivalue)
{
Console.WriteLine("Thats not a number, try again");
}
Okay so i'm trying to load up a bunch of profiles through C# and I keep getting this error when I try to start up the program.
C:\C#FILES>program.exe
Unhandled Exception: System.IndexOutOfRangeException: Index was outside the boun
ds of the array.
at ConsoleApplication2.Program.loadAccounts()
at ConsoleApplication2.Program.Main(String[] args)
C:\C#FILES>
i've investigated and i think it has to do with the format of the accounts in the file
i'm wondering what the proper way is, i've tried every way i can think of
here's the loading accounts method
private static void loadAccounts()
{
using (TextReader tr = new StreamReader("accounts.txt"))
{
string line = null;
while ((line = tr.ReadLine()) != null)
{
String[] details = line.Split('\t');
accounts.Add(details[0] + ":" + details[1]);
}
}
}
the accounts.txt part is the part i'm unsure about, i thought it would be as follows
username(tab)password
like this
username password
however it gives the error shown above
does anyone know what the proper account format should be?
You're getting an IndexOutOfRangeException, which suggests that details only had a single entry - which means there wasn't a tab on that line.
I suggest you print out the line in question before splitting, so you can see which line is causing problems. Or possibly do it conditionally:
while ((line = tr.ReadLine()) != null)
{
String[] details = line.Split('\t');
if (details.Length == 1)
{
// Or log it, or whatever...
Console.WriteLine("Input error: no tab in line '{0}'", line);
}
else
{
accounts.Add(details[0] + ":" + details[1]);
}
}
This is occurring because the line you are splitting from your input does not contain the elements requested.
It is unlikely that the first (read: 0th) element in the array is the cause of the issue because of the way that .NET deals with Split.
Have you check that there are no blank lines in your input file? A single blank line (even at the end of the file) would cause this issue.
There are multiple checks you could add such as..
if(!string.IsNullOrWhitespace(line)) ...
or
if(details.Length > 1)
These are a few checks, either or both I would recommend implementing (there are more to consider) otherwise you are just blindly trusting input values and that is not good practice in general.
For logging purposes
__LINE__
__FILE__
were my friends in C/C++. In Java to get that information I had to throw an exception and catch it. Why are these old standbys so neglected in the modern programming languages? There is something magical about their simplicity.
Caller Information has been added to .NET 4.5. This will be compiled, a big improvement over having to examine the stack trace manually.
public void Log(string message,
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0)
{
// Do logging
}
Simply call it in this manner. The compiler will fill in the file name and line number for you:
logger.Log("Hello!");
It is uglier, but you can do something like this in C# using the StackTrace and StackFrame classes:
StackTrace st = new StackTrace(new StackFrame(true));
Console.WriteLine(" Stack trace for current level: {0}", st.ToString());
StackFrame sf = st.GetFrame(0);
Console.WriteLine(" File: {0}", sf.GetFileName());
Console.WriteLine(" Method: {0}", sf.GetMethod().Name);
Console.WriteLine(" Line Number: {0}", sf.GetFileLineNumber());
Console.WriteLine(" Column Number: {0}", sf.GetFileColumnNumber());
Of course, this comes with some overhead.
With Caller Information (introduced in .NET 4.5) you can create the equivalent of __LINE__ and __FILE__ in C#:
static int __LINE__([System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
{
return lineNumber;
}
static string __FILE__([System.Runtime.CompilerServices.CallerFilePath] string fileName = "")
{
return fileName;
}
The only thing to remember is that these are functions and not compiler directives.
So for example:
MessageBox.Show("Line " + __LINE__() + " in " + __FILE__());
If you were to use this in practise then I'd suggest different names. I've used the C/C++ names just to make it clearer what they are returning, and something like CurrentLineNumber() and CurrentFileName() might be better names.
The advantage of using Caller Information over any solution that uses the StackTrace is that the line and file information is available for both debug and release.
The closest thing to those is the fact that you can create a StackTrace object and find out the name of the method at the top of the stack, so you can get close to the functionality of the __FUNCTION__ macro.
StackTrace stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames();
foreach (StackFrame stackFrame in stackFrames)
Console.WriteLine(stackFrame.GetMethod().Name);
To reduce the cost of typing this out by hand, and also the runtime code, you can write a helper method:
[Conditional("Debug")]
public void LogMethodName()
{
Trace.WriteLine("Entering:" + new StackTrace().GetFrame(1).GetMethod().Name);
}
Note how we get frame 1, as frame 0 would be LogMethodName itself. By marking it as Conditional("Debug") we ensure that the code is removed from release builds, which is one way to avoid the runtime cost where it may not be needed.
Because the stack trace contains most of what you need. It will not give you the name of the file but it will give you the class/method name. It also contains the line number. It is not neglected it is automatic. You just need to throw an exception like you do it in Java
Here's a way to get the line number: http://askville.amazon.com/SimilarQuestions.do?req=line-numbers-stored-stack-trace-C%2523-application-throws-exception
If you use log4net, you can get the line number and file name in your logs, but:
it can decrease your app. performance
you have to have .PDB files together with your assemblies.
There are already some suggestions to achieve what you want. Either use the StackTrace object or better log4net.
In Java to get that information I had to throw an exception and catch it.
That's not quite true. You can have it without throwing exceptions, too. Have a look to log4j. It even logs your method and class name, without polluting your code with hard coded strings containing the current method name (at least I have seen this in some occasions).
Why are these old standbys so neglected in the modern programming languages?
Java and C# don't make use (in the latter: excessive use) of preprocessors. And I think it's good. Abusing preprocessors to make unreadable code is very easy. And if programmers can abuse some technique ... they will abuse it.
Just a note about performance, which is very likely to be the next thing, which pops up in your mind:
If you use StackTrace or log4net you will always will read or hear that it is slow, because it uses Reflection. I am using log4net and I never encountered logging as a performance bottle neck. If it would be, I can declaratively deactivate (parts of) logging -- without changing the source code. That's pure beauty compared to delete all the logging lines in C/C++ code! (Besides: If performance is a primary goal, I would use C/C++ ... it will never die despite of Java and C#.)
Having used the FILE and LINE macros for many years for logging in C/C++ I really wanted a similar solution in C#. This is my solution. I prefer it to #fostandy suggestion of creating many overloads with varying number of parameters. This seems the less intrusive and does not limit the number of formatted parameters. You just have to be willing to accept the addition of the F.L() parameter at start of every Log.Msg() call.
using System;
using System.Runtime.CompilerServices;
namespace LogFileLine
{
public static class F
{
// This method returns the callers filename and line number
public static string L([CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
{
// Remove path leaving only filename
while (file.IndexOf("\\") >= 0)
file = file.Substring(file.IndexOf("\\")+1);
return String.Format("{0} {1}:", file, line);
}
}
public static class Log
{
// Log a formatted message. Filename and line number of location of call
// to Msg method is automatically appended to start of formatted message.
// Must be called with this syntax:
// Log.Msg(F.L(), "Format using {0} {1} etc", ...);
public static void Msg(string fileLine, string format, params object[] parms)
{
string message = String.Format(format, parms);
Console.WriteLine("{0} {1}", fileLine, message);
}
}
class Program
{
static void Main(string[] args)
{
int six = 6;
string nine = "nine";
string dog = "dog";
string cat = "cats";
Log.Msg(F.L(), "The {0} chased the {1} {2}", dog, 5, cat);
Log.Msg(F.L(), "Message with no parameters");
Log.Msg(F.L(), "Message with 8 parameters {0} {1} {2} {3} {4} {5} {6} {7}",
1, 2, 3, "four", 5, 6, 7, 8.0);
Log.Msg(F.L(), "This is a message with params {0} and {1}", six, nine);
}
}
}
Here's the output from this code above
Program.cs 41: The dog chased the 5 cats
Program.cs 43: Message with no parameters
Program.cs 45: Message with 8 parameters 1 2 3 four 5 6 7 8
Program.cs 48: This is a message with params 6 and nine