It just seems a mess to me, my mind tells me there has to be a better way.
I have 6 controls on a web page.
if (printer_make_1.Text != "" && printer_model_1.Text != "" && printer_make_2.Text != "" && printer_model_2.Text != "" && printer_make_3.Text != "" && printer_model_3.Text != "")
{
// Do something
}
What is the best/most efficient way to do this?
You can refactor into a method, if you want to improve the readability or use the same logic elsewhere:
public Boolean AllControlsHaveAValue() {
return (printer_make_1.Text != ""
&& printer_model_1.Text != ""
&& printer_make_2.Text != ""
&& printer_model_2.Text != ""
&& printer_make_3.Text != ""
&& printer_model_3.Text != "");
}
Then just ask:
if (AllControlsHaveAValue()) {
// do something
}
Restructuring starts with your data: avoid printer_make_1, printer_make_2, ...
class PrinterData
{
public string Make { get; set; }
public string Model { get; set; }
}
PrinterData[] printers = new PrinterData[3]; //or use a List<>
printers[0] = new PrinterData { Make = "PH", Model = "1A" };
...
if (printers.All(p => ! (p.Make == "" || p.Model == "")) )
...
if(new[] { printer_make_1, printer_model_1 ...}.All(l => l.Text != string.Empty)
{
//do something
}
You might want to split it up to be more readable:
var labels = new[] { printer_make_1, printer_model_1 ... };
if(labels.All(l => l.Text != string.Empty))
{
//do something
}
I normally put that test into a method and call that to make the if easier to read
private boolean AreAllPrinterFieldsFilled()
{
return (printer_make_1.Text != ""
&& printer_model_1.Text != ""
&& printer_make_2.Text != ""
&& printer_model_2.Text != ""
&& printer_make_3.Text != ""
&& printer_model_3.Text != "");
}
Then in the if:
if (AreAllPrinterFieldsFilled)
{
// Do something
}
There are lots of ways to accomplish this - none of them are elegant. Do what is most readable to you (and those who may come behind you).
I would probably take this approach:
string makeText = String.Concat(printer_make_1.Text, printer_make_2.Text, printer_make_3.Text);
string modelText = String.Concat(printer_model_1.Text, printer_model_2.Text, printer_model_3.Text);
if (makeText.Length != 0 && modelText.Length != 0)
{
// Do something
}
if (!Enumerable.Range(1, 3)
.Any(i => ((TextBox)FindControl("printer_make_" + i)).Text == "" ||
((TextBox)FindControl("printer_model_" + i)).Text == "") {...}
It allows you to later expand the number of printer makes and models, but isn't as strong typed.
private bool CheckAllEmpty(params TextBox[] textBoxes)
{
return textBoxes.All(tb => tb.Text != null);
}
private void Foo()
{
...
if (CheckAllEmpty(tb1, tb2, tb3))
{
mbox("tb1, tb2 and tb3 are all empty");
}
else
{
mbox("tb1, tb2 or tb3 isn't empty");
}
...
}
Related
I have a ConcurrentDictionary of Attributes for products. These attributes have the product ID and values for the names of the attribute and any options the attribute has. I have this ConcurrentDictionary because I have threads that are created to handle each attribute in the dictionary by attribute name.
if (knownAttribute.AttributeType.Value.Equals("Product Specification"))
{
Console.WriteLine("Started a thread for: " + knownAttribute.AttributeTypeId + ", " + knownAttribute.Value);
while (true)
{
/* if (AS400SpecificationAttributes.IsEmpty && knownSpecificationBag.IsEmpty && gatherRowsTasks.All(x => x.IsCompleted))
break;*/
AS400SpecificationAttribute AS400SpecificationAttributeWork = null;
AS400SpecificationAttributeWork = knownSpecificationBag.Keys.FirstOrDefault(x => x.AttributeName == knownAttribute.Value);
if (AS400SpecificationAttributeWork != null)
{
var product = ctx.Products.FirstOrDefault(x => x.ProductNumber == AS400SpecificationAttributeWork.ProductNumber);
if (product == null)
continue;
var productAttribute = new ProductAttribute();
productAttribute.Attribute = knownAttribute;
if (AS400SpecificationAttributeWork.AttributeValue != null)
{
var knownAttributeOption = ctx.AttributeOptions.FirstOrDefault(x => x.Attribute.Equals(knownAttribute) && x.Value.Equals(AS400SpecificationAttributeWork.AttributeValue));
if (knownAttributeOption == null)
{
knownAttributeOption = new AttributeOption();
knownAttributeOption.Value = AS400SpecificationAttributeWork.AttributeValue;
knownAttributeOption.Attribute = knownAttribute;
ctx.AttributeOptions.InsertOnSubmit(knownAttributeOption);
ctx.SubmitChanges();
}
productAttribute.AttributeOption = knownAttributeOption;
productAttribute.AttributeOptionId = knownAttributeOption.Id;
}
product.ProductAttributes.Add(productAttribute);
ctx.SubmitChanges();
string tmpstr = null;
if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr))
Thread.Sleep(50);
}
else
{
if (tryCounter < 5)
{
tryCounter++;
Thread.Sleep(1000);
Console.WriteLine("Thread waiting for work: Product Specification:" + knownAttribute.Value);
continue;
}
else
{
int outVal;
threadTracker.TryRemove("Product Specification:" + knownAttribute.Value, out outVal);
Console.WriteLine("Closing Thread: Product Specification:" + knownAttribute.Value);
break;
}
}
Thread.Sleep(50);
}
It seems like the following Attribute element refuses to be removed.
I don't understand why. If i put it in a while(!dic.tryRemove(ele)) it will forever be stuck and never move from there.
There may be an error somewhere within the thread but I have no idea why.
This statement
if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr))
will always return true or false. It won't block. That's the behavior of ConcurrentDictionary. It will return false if the key is not in the dictionary.
If you're looping while that method returns false and it's stuck, that means that the item isn't in the dictionary when the loop begins. Either it either was never in the dictionary or that another thread already removed it.
Is your intention to loop until the item is not in the dictionary?
You could try this:
if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr)
&& !knownSpecificationBag.ContainsKey(AS400SpecificationAttributeWork))
Implement proper equals and gethashcode when using TryRemove
public override int GetHashCode()
{
return new { this.name, this.value, this.group, this.productNumber }.GetHashCode();
}
public bool Equals(AS400SpecificationAttribute other)
{
if (other == null)
return false;
return (this.ProductNumber.Equals(other.productNumber) && ((this.group != null && this.group.Equals(other.AttributeGroup)) || (this.group == null && other.AttributeGroup == null)) && ((this.name!= null && this.name.Equals(other.AttributeName)) || (this.name == null && other.AttributeName == null)) && ((this.value != null && this.value.ToUpper().Equals(other.AttributeValue.ToUpper())) || (this.value == null && other.AttributeValue == null)));
}
I have an IF statement that is supposed to make sure the TextBox1.Text and TextBox2.Text do not match or are not blank. If they don't match or are not blank then it is supposed to assign the text in the boxes to two string variable. What I can't figure out is why when I leave the two textboxes blank the true statement still fires.
if ((tbStartBreak2.Text != tbEndBreak2.Text) || (tbStartBreak2.Text == "" && tbEndBreak2.Text == ""))
{
sb2 = tbStartBreak2.Text;
se2 = tbStartBreak2.Text;
}
There are two conditions in your if statement:
if ((tbStartBreak2.Text != tbEndBreak2.Text) || (tbStartBreak2.Text == "" && tbEndBreak2.Text == ""))
The first one checks to make sure they don't match (so, good). The second checks to make sure that they are blank (so, bad). You want this:
if ((tbStartBreak2.Text != tbEndBreak2.Text) || (tbStartBreak2.Text != "" && tbEndBreak2.Text != ""))
Also, what are you trying to do? The second condition is the only one you need if you really want them not to match OR not be blank - because the only time this will be false is if they are both blank.
You wrote "OR textbox are blank", you need "OR textbox are not blank"
if ((tbStartBreak2.Text != tbEndBreak2.Text) || (tbStartBreak2.Text != "" && tbEndBreak2.Text != ""))
{
sb2 = tbStartBreak2.Text;
se2 = tbStartBreak2.Text;
}
As a side note, I'd replace "" with string.Empty for readability.
if ((tbStartBreak2.Text != tbEndBreak2.Text) || (tbStartBreak2.Text != string.Empty && tbEndBreak2.Text != string.Empty))
{
sb2 = tbStartBreak2.Text;
se2 = tbStartBreak2.Text;
}
And for even more readability, you can extract these big conditions
if (TextboxesDoNotMatch() || TextboxesAreNotEmpty())
{
sb2 = tbStartBreak2.Text;
se2 = tbStartBreak2.Text;
}
private bool TextboxesDoNotMatch()
{
return tbStartBreak2.Text != tbEndBreak2.Text;
}
private bool TextboxesAreNotEmpty()
{
return tbStartBreak2.Text != string.Empty && tbEndBreak2.Text != string.Empty;
}
If you want it to return that they are NOT blank then you need to do this
(tbStartBreak2.Text != "" && tbEndBreak2.Text != "")
you have an OR between both conditions so when both are empty the second part will be true regardless the first part
(tbStartBreak2.Text == "" && tbEndBreak2.Text == "")
I got 2 datagrid views, First datagrid 1st col or Index 0 & the Second datagrid 1st col or Index 0.
How can i loop through a specific col in the datagridviews and look for the string values,if it matches with the list then go to a function.
My approach is not working. How can i do this?
private void b_calculate_Click(object sender, EventArgs e)
{
List<string> value = new List<String>() { "AE0", "AT1", "AT2", "AT3"};
value = new List<string>(datagridview1.Columns[0].Index);
List<string> value2 = new List<String>() { "BE0", "BT1", "BT2", "BT3"};
value2 = new List<string>(datagridview2.Columns[0].Index);
//First Combination
if((value.ToString() == "AT1" || value.ToString() == "AE0" ||
value.ToString() == "AT2")
&&
(value2.ToString() == "BT1" || value2.ToString() == "BE0"))
{
gottoFunction1();
}
//Second Combination
if((value.ToString() == "AT1" || value.ToString() == "AT2" )
&&
(value2.ToString() == "BT1" || value2.ToString() == "BT2"))
{
gottoFunction2();
}
}
Here's a routine that iterates through all available rows in both DataGridViews and does the processing shown in your method:
private void b_calculate_Click(object sender, EventArgs e)
{
for (var i = 0; i < dataGridView1.RowCount; i++)
{
if (dataGridView2.RowCount <= i)
break;
var cellFromDG1 = dataGridView1.Rows[i].Cells[0];
var cellFromDG2 = dataGridView1.Rows[i].Cells[0];
if (cellFromDG1.Value == null || cellFromDG2.Value == null)
{
// this could be the empty row that allows you to
// enter a new record
continue;
}
var value = cellFromDG1.Value.ToString();
var value2 = cellFromDG2.Value.ToString();
if ((value == "AT1" || value == "AE0" || value == "AT2") &&
(value2 == "BT1" || value2 == "BE0"))
{
gottoFunction1();
}
if ((value == "AT1" || value == "AT2") &&
(value2 == "BT1" || value2 == "BT2"))
{
gottoFunction2();
}
}
}
I have a form in which there are many textBoxes from which three textboxes are required to fill in order to submit the form. I dont want to use each If block for each text box. Is there any way to use a single if statement for all the three text boxes? I am using the following code:
if (textBox1.Text != "" || textBox2.Text != "" || textBox4.Text != "")
{
// Code
}
else
{
MessageBox.Show("Fill required fields");
}
but this code works even a single text fox is filled and the rest of the required text boxes are empty.
if (textBox1.Text != "" && textBox2.Text != "" && textBox4.Text != "")
{
// Code
}
else
{
MessageBox.Show("Fill required fields");
}
You want all conditions to pass. This fits the semantics of the logical AND operator &&.
If you have tons of textboxes, I would tend to keep them in a list:
var boxes = new List<TextBox>{
textBox1,
textBox2,
textBox3,
//...
};
if (boxes.Any(tb => string.IsNullOrEmpty(tb.Text)))
{
MessageBox.Show("Fill required fields");
}
else
{
// Code
}
I also tend to prefer to keep the exception in the if part, returning or throwing an error and ommit an else part, since that is just normal code flow. This keeps the code you expect to run as far to the left as possible.
You should change || to &&
You created a collection of or statements, so only one needs to be true in order to continue. Instead you need to and them:
if (textBox1.Text != "" && textBox2.Text != "" && textBox4.Text != "")
You may define a method to test empty strings.
public class Test
{
public static bool IsEmpty(params string []args)
{
if (args.Length == 0) return true ;
return args.Any(p => string.IsNullOrEmpty(p));
}
}
To test strings,
if(!Test.IsEmpty(TextBox1.Text,TextBox2.Text,TextBox3.Text))
{
//valid
}
You use OR (||) and should use AND (&&) instead. You want ALL three textboxes to be non-empty strings. Check out the following code:
if (textBox1.Text != String.Empty && textBox2.Text != String.Empty && textBox4.Text != String.Empty)
{
// Code
}
else
{
MessageBox.Show("Fill required fields");
}
You can also make a collection of TextBoxes and loop through them to check for non-empty Strings. Something like this:
List<TextBox> _lstTextBoxes = new List<TextBox>();
_lstTextBoxes.Add(textBox1);
_lstTextBoxes.Add(textBox2);
_lstTextBoxes.Add(textBox3);
Boolean checkFailed = false;
foreach(TextBox tb in _lstTextBoxes)
if(tb.Text == String.Empty)
checkFailed = true;
if(checkFailed)
MessageBox.Show("Fill required fields");
else
//code
This way you have a more generic approach to which you can easily add or remove certain textboxes.
Instead of using OR (||) use AND (&) in your condition.
Suggestion
Use Trim function from string to remove any white spaces from textbox (if required)
Instead of comparing like textBox1.Text != "" do String.IsNullOrEmpty(textBox1.Text) == false
Assuming you have 4 textboxes in total, below code will work
if ((textBox1.Text != "" && textBox2.Text != "" && textBox3.Text != "") || (textBox1.Text != "" && textBox2.Text != "" && textBox4.Text != "") ||
(textBox1.Text != "" && textBox3.Text != "" && textBox4.Text != "") || (textBox2.Text != "" && textBox3.Text != "" && textBox4.Text != "")
)
{
// Code
}
else
{
MessageBox.Show("Fill required fields");
}
I have the following code on an asp.net button click
if(str == ipaddr1 || ipaddr2 || ipaddr3 || ipaddr4 || ipaddr5 || ipaddr6 || ipaddr7)
// do this
else
//cancel click event
How can I optimize this piece of code?
Update: Apologies everyone! I did not mean to compare it with the literal string ipaddr. I mean to compare it to the value ipaddr1, ipaddr2 holds and so on
replace with:
Regex.IsMatch(str, "^ipaddr[1-7]$")
Optimised for readability not necessarily performance.
HashSet<T> is the best container to check containing:
var ips = new HashSet<string> { "ip1", "ip2", "ip3", "ip4", "ip5" };
if (ips.Contains(input))
{
// do stuff
}
For any type:
var ips = new HashSet<IPHostEntry> { ip1, ip2, ip3, ip4, ip5 };
if (ips.Contains(input))
{
// do stuff
}
Was:
if(str = qry.StartsWith("23.55") || str = qry.StartsWith("xuz") || str = qry.StartsWith("i3") || str = qry.StartsWith("i444") || str = qry.StartsWith("ki5") || str = qry.StartsWith("65fr6")) // do this else // do this
Become:
var arr = new[] { "23.55", "xuz", "i3", "i444", "ki5", "65fr6") };
if (arr.Any(str => input.StartsWith(str, StringComparison.Ordinal))
{
// do stuff
}
StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase are very important for performance.
What about
if(str.Substring(0,6) == "ipaddr" && str[6] >= '1' && str[6] <= '7')
For your information, your original code does not even compile. This
if(str == "ipaddr1" || "ipaddr2" || "ipaddr3" || "ipaddr4" || "ipaddr5" || "ipaddr6" || "ipaddr7")
Needs to be replaced with this to compile
if(str == "ipaddr1" || str == "ipaddr2" || str == "ipaddr3" || str == "ipaddr4" || str == "ipaddr5" || str == "ipaddr6" || str == "ipaddr7")
So the original code is actually even more tedious than you thought.
UPDATE
According to your updated question, the best option is to put your string variables into a List<string> called, for example ipaddr. Then to see if the string str is included, simply do this:
if( ipaddr.Contains( str ) )
{
//contained in the list
}
I would do something like:
str.Length == 7 && str.StartsWith("ipaddr") && str[6] > '0' && str[6] < '8'
Edit:
After your update, I would do something like:
string[] validStrings = { ipaddr1, ipaddr2, ... };
bool isStrValid = validStrings.Contains(str);
For better performance, consider using a HashSet<string> instead of an array, especially if the list of valid strings doesn't change.
Both more readable, and more performant would be:
switch(str)
{
case "ipaddr1":
case "ipaddr2":
case "ipaddr3":
case "ipaddr4":
case "ipaddr5":
case "ipaddr6":
case "ipaddr7":
//do something
break;
default:
//do something else
break;
}
(although, admittedly massively verbose...)
I would do a
List<string> variables = new List<string> { "ip1","ip2","ip3","ip4","ip5" };
if (variables.Contains(inputstring))
...