I'm writing some error checking and trying to make use of an boolean array to store true or false in the elements and then my final condition parses through the stored elements to determine if its all true in visual studio 2008. Theres probably a easier way to do the error checking, but might as well learn how to utilize an array. Here's what I have so far
bool[] checker = new bool[1]; // declared array...I think
private void print_button_Click(object sender, EventArgs e)
{
if (authorbox.Text == "")
{
MessageBox.Show("Author field empty", "Required Entry");
}
else
{
checker[0] = true; // assigning element to array correctly?
}
if (titlebox.Text == "")
{
MessageBox.Show("Title field Empty", "Required Entry");
}
else
{
checker[1] = true;
}
// The part I am having trouble with basically if any of my array elements are
// false don't execute printing. Else go ahead and print.
if ()
{
}
else
{
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.ShowDialog();
}
}
If you are using .NET 3.5 you can use Any and All to see if any of the booleans are true, or if all of them are true:
if (checker.Any(x => x))
or:
if (checker.All(x => x))
Also, if you want an array of two booleans, you should use new bool[2] not new bool[1]. It would be easier to use a List<bool> though.
instead of using the array it would be much easier to simply exit the method as soon as an error is detected:
private void print_button_Click(object sender, EventArgs e) {
if (authorbox.Text == "") {
MessageBox.Show("Author field empty", "Required Entry");
return;
}
if (titlebox.Text == "") {
MessageBox.Show("Title field Empty", "Required Entry");
return;
}
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.ShowDialog();
}
Well this is not the ideal way for error handling but you can use the .Contains() Method.
if (checker.Contains(false))
{
// Do Something
}
else
{
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.ShowDialog();
}
Apart from other things, you should say
bool[] checker = new bool[2];
if you want an array consisting of 2 elements ;) In this particular case the array doesn't seem to make too much sense, because it obfuscates things a little bit. You could do the same thing with just one boolean variable.
Using boolean arrays to accumulate a single go/no-go value is overkill. There are more useful things you could play with to get the hang of arrays.
You're better off simply ANDing the results of your intermediate checks into a value and then checking that for true/false:
public bool CheckControls()
{
bool pass = true;
pass &= !string.IsNullOrEmpty(authorbox.Text));
pass &= !string.IsNullOrEmpty(titlebox.Text));
// if any of these are empty then pass is to false and stays that way.
return pass;
}
If you need to keep track of which intermediate test failed, then consider using an integer and predefined constants of powers of two. Here you instead check for zero if all is well. This allows you to mask against the returned value and accumulate any combination of test results. As long as you have less than 32 (or 64) tests.
int AUTHORBOX = 2;
int TITLEBOX = 4;
int ISBNBOX = 8;
int PRICEBOX = 16;
public int AlternateCheck()
{
int temp = 0;
temp += string.IsNullOrEmpty(authorbox.Text) ? AUTHORBOX : 0;
temp += string.IsNullOrEmpty(titlebox.Text) ? TITLEBOX : 0;
temp += string.IsNullOrEmpty(isbnbox.Text) ? ISBNBOX : 0;
temp += string.IsNullOrEmpty(pricebox.Text) ? PRICEBOX : 0;
return temp;
}
I'm pretty sure the Contains method suggested by NebuSoft is a LINQ extension and therefore not available in .NET 2.0. You could however use the Array.IndexOf<T> method, like this:
if (Array.IndexOf<bool>(checker, false) != -1)
{
// some element in the array is false
}
else
{
// no false in the array
}
However, NebuSoft is right in asserting that this isn't the best approach. If you're curious to know more, I'll be happy to discuss it further.
Related
I am trying to write a program that lets me enter a list of names with their respective film rating into an array (Would do a list but the course material wants me to use array). Before I add the names to the array I want to make sure that a valid rating has been entered.
I am currently using a for statement that cycles through he array length and lets the user enter each movie to the list that way. This happens in a while loop to make them re-enter the name if the rating is invalid before the name is committed to Array. I check the names by calling a method with a temporary string assigned with the current entered name and rating which will do some conditional checks and return either false or true depending on the outcome. But the way I am doing it is not working at all..
Problem is that I have no idea how to make practical use of the bool statement my method returns:
string[] filmNames = new string[ArrayLength];
for (int i = 0; i < filmNames.Length; i = i + 1)
{
bool ratingFail = true;
int displayNumber = i + 1;
while (ratingFail)
{
Console.Write($"> Enter the Name and Rating of film number {displayNumber} of {ArrayLength}: ");
string checkRating = Console.ReadLine();
CheckRating(checkRating); // currently just does "return false;" for testing purposes
if (true) // this statement is clearly not effected by whatever the return value is from above method. Why? What to do?
{
ratingFail = true;
}
else
{
filmNames[i] = checkRating; // this bit is marked as unreachable, which is is.
ratingFail = false;
}
}
}
my test method:
public static bool CheckRating(string checkRating)
{
return false;
}
I am VERY (a week) new to programming and C# so please keep in mind when answering that I may not understand particular lingo referring to programming terms outside of the scope of what you can see here within, but I will Google and research to the best of my abilities if there is no way to simplify what you want to say. Thank you for your time and effort.
if (true) // this statement is clearly not effected by whatever the return value is from above method. Why? What to do?
{
ratingFail = true;
}
This will always be true, because you're creating a variable that is always true. You want this:
ratingFail = CheckRating(checkRating)
if (!ratingFail) {
The rating is valid, do stuff here.
}
If ratingFail is true, the loop will continue.
This assumes that CheckRating returns true if the input is invalid, and false if it is valid. The variable naming here is pretty confusing, and I recommend you refactor.
I would do it this way, assuming CheckRating returns true if valid:
for (int i = 0; i < filmNames.Length; i = i + 1)
{
bool ratingValid; // Defaults to false
int displayNumber = i + 1;
while (!ratingValid)
{
Console.Write($"> Blablabla: ");
string input = Console.ReadLine();
ratingValid = CheckRating(input);
}
// Do stuff if rating is valid here. If you got here, rating is valid.
}
// edit by iluvpancakes //
I decided to add a comment made by #Sinatr since that was the (version of the) solution I personally ended up using:
if(CheckRating(checkRating))
{
[do stuff and things]
}
bool ret = CheckRating(checkRating); // currently just does "return false;" for testing purposes
if (ret)
{
[...]
}
Or, like Sinatr's comment:
if(CheckRating(checkRating))
{
[...]
}
So I need to count lines in a textbox, to do this i use:
if (subject.Length <= 20)
{
bool moreLines = true;
int onLine = 2;
int count = 0;
while (moreLines)
{
textBody[count] = TextBox_Text.Text.Split('\n')[onLine];
Console.WriteLine("Line saved: " + textBody[count]);
onLine++;
count++;
try
{
if (TextBox_Text.Text.Split('\n')[onLine] == null)
{
}
}
catch (IndexOutOfRangeException)
{
moreLines = false;
}
}
return true;
}
I insert the split strings into textBody[] array but once I approach the last lines where there is no text I want the loop to stop. I tried to do an if statement which checks if the next line is null, and if yes stop the loop. However, I kept getting an IndexOutOfRangeException so I just put the whole thing in a try catch, but I feel like there would be an easier way to do this?
I think you might have over complicated things massively.
The String.Split method have multiple overloads, some of them takes as an argument a member of the StringSplitOptions enum - one of it's members is called None, and the other is called RemoveEmptyEntries - so as far as I understand, all you need is this:
var textBody = TextBox_Text.Text.Split(
new char[] {'\n'},
StringSplitOptions.RemoveEmptyEntries);
An easy way to do this would just to use the following:
TextBox_Text.Text.Split('\n').Length
The Length property returns the length of the array.
so I just used the LineCount property instead and done a compare to the onLine
if (TextBox_Text.LineCount >= onLine)
{
moreLines = false;
}
private bool DataValidation(string Checker)
{
int i;
if (Int32.TryParse(Checker, out i))
{
return true;
}
else
{
return false;
}
}
private void NumberChecker()
{
if (int.Parse(txtRank.Text) >= 0 || int.Parse(txtRank.Text) <= 50)
{
errorProvider1.SetError(txtRank, string.Empty);
errorProvider1.Clear();
}
else
{
errorProvider1.SetError(txtRank, "Between 1 and 50 please!");
}
}
private void txtRank_Validating(object sender, CancelEventArgs e)
{
if (DataValidation(txtRank.Text) == false)
{
errorProvider1.SetError(txtRank, "Must be numeric!");
}
else
{
errorProvider1.SetError(txtRank, string.Empty);
errorProvider1.Clear();
}
NumberChecker();
}
I've been trying to get this to work for about 4 hours, can someone please tell me why it keeps saying "String in the wrong format" I've tried all of this inside the the validation event, nothing I do is working. I am not understanding why.
Update:
private void txtRank_Validating(object sender, CancelEventArgs e)
{
if (DataValidation(txtRank.Text) == false)
{
errorProvider1.SetError(txtRank, "Must be numeric!");
}
else
{
errorProvider1.SetError(txtRank, string.Empty);
errorProvider1.Clear();
}
if (Convert.ToInt32(txtRank.Text) >= 0 && Convert.ToInt32(txtRank.Text) <= 50)
{
errorProvider1.SetError(txtRank, string.Empty);
errorProvider1.Clear();
}
else
{
errorProvider1.SetError(txtRank, "Between 1 and 50 please!");
}
}
if i use the code above, i can either do one or the other, but i have to comment out a section of code in order to do that.
You're doing a lot of stuff here that isn't necessary at all.
First off: Assuming that the if statement in your DataValidation method is only intended to have the return true and return false, the if statement is totally unnecessary. You could just say return Int32.TryParse(Checker, out i); and it would do the exact same thing. In fact, you could remove the int i in the first place, and just do this:
private bool DataValidation(string Checker) {
return Int32.TryParse(Checker, out int i);
}
out int i creates a temporary variable... and since the DataValidation method is now a single method call, you may realize that the whole method is now unnecessary. You could simply replace any call to DataValidation(someString) with Int32.TryParse(someString, out int i) with no side effects.
Moving on to your NumberChecker method, the error becomes immediately apparent:
if (int.Parse(txtRank.Text) >= 0 || int.Parse(txtRank.Text) <= 50)
This is the only place in your code where you are parsing a string without checking to ensure that it's a number first. Evidently, txtRank.Text is a string that is not a proper number. This is actually where TryParse would come in handy.
I'm going to assume that you don't know exactly what TryParse does and that you were only using it as an error checker, which is okay, because the function of out arguments aren't immediately apparent.
The out keyword, effectively, allows a function to change the thing that was passed in. Take the following code snippet:
public static void Main(string[] args)
{
String foo = "abc";
DoSomething(out foo);
Console.WriteLine(foo);
}
private static void DoSomething(out String something)
{
something = "def";
}
Despite DoSomething not returning a value, the Console.WriteLine(foo); will write def rather than abc. Int32.TryParse uses this to its advantage: It returns a bool that says whether the operation was successful or not. And if it was successful, it stores the result in the variable used as the out argument.
As such, your NumberChecker method should look something like this:
private void NumberChecker()
{
int num = null;
if (Int32.TryParse(txtRank.Text, out num) {
// if TryParse returns true, then we have a result in `num`.
if (num >= 0 && num <= 50)
{
errorProvider1.SetError(txtRank, string.Empty);
errorProvider1.Clear();
}
else // txtRank.Text is a number, but is not within the range
{
errorProvider1.SetError(txtRank, "Between 1 and 50 please!");
}
}
else // txtRank.Text is not a number to begin with
{
errorProvider1.SetError(txtRank, "txtRank.Text is not a number!");
}
}
Worth noting: Since NumberChecker() can now handle the case of invalid text like txtRank_Validating() used to, you can now remove txtRank_Validating() as well. NumberChecker() is now the only necessary code.
One final thing worth noting: In your original code, although your txtRank_Validating() has if statements for in case txtRank.Text was not a number, the reason it was still failing was because NumberChecker() was called at the end of the method whether the text was a number or not. In that sense, the easiest solution would have just been to move the NumberChecker(); call to after errorProvider1.Clear(); inside the else block. But I think the rest of the details in this answer are worth taking note of.
I have this code to validate a phone number but it looks a bit awkward. I'm guessing theres a better way to go about this. How can I make this more efficient?
public static bool validTelephoneNo(string telNo)
{
bool condition = false;
while (condition == false)
{
Console.WriteLine("Enter a phone number.");
telNo = Console.ReadLine();
if (telNo.Length > 8)
{
if (telNo.StartsWith("+") == true)
{
char[] arr = telNo.ToCharArray();
for (int a = 1; a < telNo.Length; a++)
{
int temp;
try
{
temp = arr[a];
}
catch
{
break;
}
if (a == telNo.Length - 1)
{
condition = true;
}
}
}
}
}
return true;
}
Don't try and do this yourself, use a library where someone has already done the hard work for you, such as libphonenumber.
Example:
public static bool validTelephoneNo(string telNo)
{
PhoneNumber number;
try
{
number = PhoneNumberUtil.Instance.Parse(telNo, "US"); // Change to your default language, international numbers will still be recognised.
}
catch (NumberParseException e)
{
return false;
}
return number.IsValidNumber;
}
This library will handle parsing and formatting phone numbers from different countries. Not only will this ensure that the number is valid in the relevant country, it will also allow you to filter out premium numbers and "fake" numbers (such as 555 in the US).
Your goal can be easily achieved using regular expressions:
public static bool validTelephoneNo(string telNo)
{
return Regex.Match(telNo, #"^\+\d{1,7}$").Success;
}
This pattern is exactly as stated: consists of integers, is less than 8 digits in length and has a plus at the start, and also this pattern can be modified if conditions somehow more complex.
try
Console.WriteLine("Enter a phone number.");
bool isValid = new System.Text.RegularExpressions.Regex(#"^[+]\d{1,7}$").IsMatch(Console.ReadLine());
Where the regex checks whether there is only a single number (1 to 7 digits) with + in front of them read. The drawback, this way you cannot further processed, you might need to read the line from console to a new variable.
I know this is a very newbie C# question but I am implementing a small program which does the following:
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
bool isRun = false;
int number = 0;
while (isRun = (true) && number < 3)
{
++number;
Console.WriteLine("Number = {0}", number.ToString());
Console.WriteLine();
}
Console.WriteLine(isRun.ToString());
Console.ReadLine();
}
}
}
At the end of the while loop, I would have expected the bool value to be true, but is is printed to be false. Why is that? Is this different from C++ where I would have done something like and the same thing in C# is giving me false
while(number<3)
{
is = true;
}
if(is){
cout<<true;
}
The reason you're seeing this behavior is due to the operator precedence involved. Here the && binds more strongly than = so the code in the loop is actually bound as the following
while (isRun = (true && number < 3)) {
...
}
Once number > 3 the && expression is false and is assigned into the isRun value and simultaneously terminates the loop. Hence once the loop exits you will see isRun as false
To get the behavior you are looking for you will need to manually correct the precedence with parens.
while ((isRun = (true)) && number < 3) {
...
}
Note: In general, as #Servey pointed out, the assignment of locals to expressions inside the loop predicate is considered bad practice. Many C# users would actually be surprised that code compiles at all because they've been conditioned to only use == in loops.
It's more idiomatic to simply set isRun to true on the first line of the loop for this pattern.
while (number < 3) {
isRun = true;
...
}
The problem is that you have set you boolean variable to false and without assigning it back to true, in while loop you are matching it against the value true, thus it fails in every case.