What is TRUE? (And Other Conversion Questions)

A grab bag of questions related to .NET and ASP.NET, an example of looping through controls on a Web page for more efficientprocessing, and a short C# odometer trick.

ask asp.netNOW

 

LANGUAGES: VB .NET | C#

TECHNOLOGIES: Conversion | Numeric and Binary Operations

 

What is TRUE? (And Other Conversion Questions)

A grab bag of questions related to .NET and ASP.NET, an example of looping through controls on a Web page for more efficient processing, and a short C# odometer trick.

 

By Josef Finsel

 

In .NET, the integer value of true is 1, correct?

- NB, Maineville, Ohio

 

The question of truth has been debated for centuries. Fortunately, we can answer this one easily enough. The answer is that non-zero equals true. What we're really dealing with is an attempt to put a lot of something into a very small container - in this case, the 65,536 values of a short int (int16 in VB .NET) into a Boolean which can only contain two. Now there are, arguably, any number of ways you can match these values up, but not many that are as clean as the way it actually works.

 

When you think of how you can group these numbers, you could say that positive numbers represent true and negative numbers represent false - but then how do you interpret zero? It's neither positive nor negative. This gives you three states (positive, negative, and zero) to try to put into two. To overcome this problem, many languages (the CLR included) tend to narrow this down to zero and non-zero, with zero representing false. It's easy enough to test whether or not this is (ahem) true with a simple piece of code:

 

StringBuilder sb = new StringBuilder();

for(short s=-5;s<=5;s++)

{

  sb.Append(s.ToString ());

  if (Convert.ToBoolean(s) )

  {

    sb.Append (" is true<hr>");

  }

  else

  {

    sb.Append (" is false<hr>");

  }

}

litOutput.Text = sb.ToString();

 

This walks through 11 variables (-5 to 5) and evaluates them as true or false, putting the results out to a literal variable and showing that zero is false while all the other values are true. The important thing to remember is this is how integers are converted into Boolean values.

 

Regardless, it's best always to define your true and false explicitly; for instance, if (x!=0) rather than if (x) when x is a integer.

 

I am trying to take a number value in several textboxes and add them together in .NET. I am then taking the total and placing it in another text box. I keep getting this error:

 

Exception Details: System.FormatException: Input string was not in a correct format.

 

- TK, Omaha, Neb.

 

This was originally sent as a VB .NET code question, so I'm going to answer that first. We'll then do a quick port to C#, because there are a couple of distinctions VB coders might be interested in. Finally, we'll wrap up with a look at a slightly bigger problem this might present.

 

The short answer is that this is a conversion problem, and all this is in the CsngDemo.aspx file. Can you tell, from this code snippet, what the problem is?

 

iNum1 = CSng(txt1.Text)

 

As long as txt1 contains a number, there's no problem. If txt1 contains either text or no value, this will throw an error because the conversion function doesn't like it. In VB .NET, it's a simple fix:

 

iNum1 = CSng(IIf(IsNumeric(txt1.Text), txt1.Text, 0))

 

In other words, if we have a numeric value in the text field, convert it; otherwise, convert the value 0. If you attempt to convert "A" to an integer, you get an error. If you attempt to convert a null value to an integer, you get an error.

 

The C# code is slightly trickier because C# doesn't have an IsNumeric function and the syntax of IIf in C# harkens back to C++.

 

Let's start with IsNumeric. Checking to see if a string is a numeric value actually is done by attempting to convert the text to an integer and then catching the error code. If no error is thrown, the text value is numeric. Because this functionality is going to be used multiple times, we'll implement it as a function:

 

public static bool IsNumeric(object value)

{

   try

   {

      int i = Convert.ToInt32(value.ToString());

      return true; }

   catch (FormatException) {return false;}

}

 

The final piece we need to handle is the IIf statement. In C# (as in C++ and C), you can handle this using the conditional expression of "? :". Just as the IIf function evaluates the first parameter then returns the second parameter if the first is true, or the third parameter if the first is false, the conditional expression in C# does the same thing. Here are two lines of code, first in VB.NET and then in C#:

 

Console.WriteLine(IIf(2+2=5, 1, 0))   ' VB.NET

Console.WriteLine((2+2==5 ? 1 : 0)); //C#

 

In both cases the code will print out a zero because 2 + 2 is not equal to 5. Now that we have it all together, we can see the C# version looks like this:

 

int iOne, iTwo, iThree, iTotal;

iOne = Convert.ToInt16(txtValue1.Text);

iTwo = Convert.ToInt16(txtValue2.Text);

iThree = IsNumeric(txtValue3.Text) ?

 Convert.ToInt16(txtValue3.Text) :

 Convert.ToInt16(0);

iTotal = iOne + iTwo + iThree;

litSum.Text  = iTotal.ToString();

 

Now, I'm only using the "fail-safe" code on the third variable because there is another valuable lesson to learn here. If you run this page and enter 10 for each text box, you'll find they add up to 30. If you change the first value to A, you'll get an error. Change it back to 10 and then change the third value to A and you won't get an error; you'll get the value of 20. This is one way to fix the problem, but there are a couple of others and they are just as important. First, you can use validator controls (see Steven Smith's article Master ASP.NET Validator Controls for more information on that) to prevent people from entering non-numeric data. But even that might not be enough. You also need to make sure they enter data that fits within the range of the variable.

 

If you've downloaded the code, you'll find a Web form named BadData.aspx. This is a simple Web form containing 100 text boxes, which all contain the value 10,000 and a button that will add up all the values. As you know, 100 * 10,000 = 1,000,000, so we know what should show up as the value. Before you press the button to find out what the results are, let's look at the code we're using to sum up the values in the text boxes:

 

foreach (Control ctrl in Page.Controls)

  {

    if(ctrl.GetType().ToString().Equals("System.Web.UI.HtmlControls.HtmlForm"))

      {

        foreach(Control tCtrl in ctrl.Controls )

         {

         if (tCtrl.GetType().ToString().Equals("System.Web.UI.WebControls.TextBox"))

           {

             wCtrl = (System.Web.UI.WebControls.TextBox)tCtrl;

             iTotal += IsNumeric(wCtrl.Text) ? Convert.ToInt16(wCtrl.Text) : Convert.ToInt16(0);

           }

         }

      }

  }

 

Rather than adding up 100 individual controls, I'm going to loop through all the controls on the page and add all the textbox controls. In addition to taking a lot less code than it would to add each text box individually, this code is flexible enough to deal with however many textboxes might be on the page. The trick is that the text-box controls aren't found at the top level, but the next level down, within the HtmlForm control. On a page this simple, I can take every textbox and process it; but, if I needed to, I could get the name of the control from wCtrl.ID, then do various processing based on the name of the variable.

 

Now, if you go ahead and press the Add button, you'll see the sum of 100 values at 10,000 each is ... 16,960?!? Yep, although only in C#. In VB .NET it raises an error. To understand what's happening, you need to take a quick look at how C# is adding numbers. Let's start with binary numbers. An 8-bit binary number has a maximum value of 255, represented in binary as 11111111. If you are using an 8-bit integer and add 1 to 255, you don't get an overflow error. Instead, it adds 1 and comes up with 100000000, and it truncates the left-most digit, leaving you with 0. Just like a car's odometer, the short variable rolls back over to 0 when it gets too much data. And, because I've defined iTotal as a short in the sample and each individual value of 10,000 is within the range of the short, the addition keeps rolling the odometer over. If you change iTotal's declaration to a larger integer, you'll get the correct answer. If you change the value of one of the text boxes to be 100,000, an overflow error gets thrown. (In VB.NET, the overflow error gets raised correctly.)

 

The moral of this story? Test your code and don't assume.

 

The files referenced in this article are available for download in both VB.NET and C#.

 

Have a question? Send it to [email protected].

 

Josef Finsel is a software consultant specializing in .NET and SQL Server. He has published a number of VB, .NET, and SQL Server-related articles and, when he isn't hanging around the aspenetpro, forums he can be found working on the syntax for FizzBin.NET, a programming language that works the way programmers have always suspected. He's also author of The Handbook for Reluctant Database Administrators (Apress).

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish