O'Reilly Forums: Errors With Chapter 4's Mileage Calculator Not Expected - O'Reilly Forums

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Errors With Chapter 4's Mileage Calculator Not Expected Pages 135-138, Chapter 4 mileage calculator not behaving as expected

#1 User is offline   Gildren 

  • Active Member
  • PipPip
  • Group: Members
  • Posts: 13
  • Joined: 20-September 13

Posted 21 February 2014 - 04:19 PM

I'm having some odd issues with the mileage calculator, on pages 135-138 of the book. When I followed the directions, the calculator worked, but as I worked through it, some odd things occurred, and I need to understand why. Here's the issues:

1. The author said you needed to cast "startingMileage" and "endingMileage" as INT for the program to work correctly. What I don't understand is we already declared "int startingMileage" and "int endingMileage" at the beginning of the program, so they were already whole numbers ... why did we have to cast them again as "int"?

2. The author noted that if you used the operators "-=" and "*=" in the problem, your result with calculating miles would be a decimal (in the example, 532.35 miles). However, when I did it, the value wouldn't calculate, and stayed at "0". It DID work when I updated the operators to "-" and "*" but I didn't get a decimal with the error -- I just got a null value. Why did my program behave differently?

3. Finally, I had a really weird issue, which is you must hit the "calculate" button FIRST before the "Display Miles" button worked. For example, if my starting mileage was 1, and my ending mileage was 11, and I clicked "calculate" I'd get $3.90, and when I clicked "Display Miles" I'd get 10. BUT -- If I clicked "Display Miles" first, it would stay the same value ... no change. Is that supposed to happen?

Thanks for the clarifications. The program worked ... I just don't fully understand WHY.
0

#2 User is offline   ClockEndGooner 

  • New Member
  • Pip
  • Group: Members
  • Posts: 8
  • Joined: 28-November 13

Posted 22 February 2014 - 08:41 PM

Hi, Gildern;

In response to your first of three issues with the Mileage Calculator, I hope the following is of help and interest to you.

C# is a strongly type language, meaning that in order for your code to execute in a consistent, reliable and robust manner, with as few, if any errors, as possible, working with value data type variables must be of the same type. The milage calculator form uses the Windows Forms NumericUpDown control, which returns the current numeric value in the control as a decimal value, not as an integer, or int. If you tried assigning the value, let's say, from the startingMilage, you would receive a compile time error message from the C# compiler, CSC.Exe, along the lines of "Cannot implicitly convert type 'decimal' to 'int'. An explicit conversion exists (are you missing a cast?)", and your source code will not be able to generate an .Exe file you can run.

The casting operation (int):

startingMileage = (int) numericUpDown1.Value;


is your way of telling the C# compiler that you want your code to intentionally assign a numeric value from a larger numeric value data type, a decimal as returned by the numericUpDown1.Value, to a smaller data type, an int (Integer, or Int32, a 32-bit integer value). Since you're being explicit in making this call, the compiler will oblige and try to convert a potentially larger numeric value stored in a decimal data type to the smaller int data type.

Hopefully, the following code fragments below might help illustrate this in a clearer way;

string trace = string.Format("int.MinValue = {0}", int.MinValue.ToString());
Console.Out.WriteLine(trace);
// Output: int.MinValue = -2147483648

trace = string.Format("int.MaxValue = {0}", int.MaxValue.ToString());
Console.Out.WriteLine(trace);
// Output: int.MaxValue = 2147483647

trace = string.Format("decimal.MinValue = {0}", decimal.MinValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimal.MinValue = -79228162514264337593543950335

trace = string.Format("decimal.MaxValue = {0}", decimal.MaxValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimal.MaxValue = 79228162514264337593543950335

decimal decimalValue = 2147500000;
trace = string.Format("decimalValue = {0}", decimalValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimalValue = 21475000

trace = 
string.Format("Difference between decimalValue and int.MaxValue = {0}",
			  ((decimal) decimalValue - int.MaxValue).ToString());
Console.Out.WriteLine(trace);
// Output: Difference between decimalValue and int.MaxValue = 16353
// This means that in the .NET Runtime support for decimal and int numeric
// data types, the current decimal value is 16,353 greater than the largest 
// positive value int value an integer value, such as staringMileage or
// endingMileage can hold.

int startingMilage = decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);
// No Output: Compiler error "Cannot implicitly 
// convert type 'decimal' to 'int'. An explicit conversion 
// exists (are you missing a cast?)" is emitted by the C# 
// Compiler and should be displayed for the source code line
// in the Errors tab and pane inside Visual Studio, and in
// the Build section of the Output pane inside Visual Studio

startingMilage = (int) decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);

// Code compiles, CSC.Exe generates the .Exe file, but a special type
// of System.Exception derived class, an OverflowException is thrown
// with the following error message: "Value was either too large or 
// too small for an Int32".  The C# compiler can't check to see if 
// the assignment from a larger decimal value to a smaller integer 
// value can take place without error, but the .NET Runtime can and 
// does.  Since this is an "exceptional" or out of the ordinary error,
// the .NET Runtime environment, which executes your program, will let 
// you know of this error by theoring an OverflowException.  I think this
// is the equivalent of trying to pour a keg of beer in a one pint glass, 
// and the .NET Runtime is letting you know there's too much beer being 
// spilled and going to waste.

decimalValue = (decimal) int.MaxValue;
trace = string.Format("decimalValue = {0}", decimalValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimalValue = 2147483647

//
// If the value in decimalValue is reduced to a value that is in
// the supported range or size of the int value, the .NET Runtime
// can automatically convert and adjust the value as needed as
// it's being stored and assigned in the startingMilage variable.
//
trace = 
string.Format("decimalValue <= int.MaxValue: {0} [{1}]",
    (decimalValue <= int.MaxValue).ToString(),
    (decimalValue <= int.MaxValue) ? "Yes" : "No");
Console.Out.WriteLine(trace);
// Output: decimalValue <= int.MaxValue: True [Yes]

startingMilage = (int) decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);
// Output: startingMilage = 2147483647

trace = 
string.Format("startingMilage == (int) decimalValue: {0} [{1}]",
    (startingMilage == (int) decimalValue).ToString(),
    (startingMilage == (int) decimalValue) ? "Yes" : "No");
Console.Out.WriteLine(trace);			  
// Output: startingMilage == (int) decimalValue: True [Yes]


If you're still wondering about casting values when assigning from one data value type to a different value data type, you might want to take a look at Chapter 4's section "Casting Call". Andrew and Jennifer do a far better job at explaining this than I can.
0

#3 User is offline   ClockEndGooner 

  • New Member
  • Pip
  • Group: Members
  • Posts: 8
  • Joined: 28-November 13

Posted 23 February 2014 - 07:22 AM

Hi, Gildren;

First and foremost, my apologies for not typing your name correctly with my original post on your casting question. No disrespect was meant or intended whatsover; it was an oversight on my part.

As for your remaining two issues, posting your actual source code for the Mileage Calculator form with the Button Click Event Handlers would be helpful to get a better idea of what's going on, especially for the second issue on using the compound operators.

I think I might have an idea as to why the "Display Miles" button doesn't change the miles traveled correctly if it is pressed before the Calculate button. If you look at the code for the Display Miles button click event handler code, button2_Click(), the method just formats a string to display the miles traveled and presents the string in a message box;

private void button2_Click(object sender, EventArgs e) 
{
    MessageBox.Show(milesTraveled + " miles", "Miles Traveled"); 
}


The code doesn't calculate or update the miles travel at all, and as a result, would not reflect the correct amount of miles traveled, if it was avaialble. To make sure that the Display Miles button click would always display the correct amount of miles traveled, you could add one line of code that programatically calls the Calculate Button's Click event handler before formatting the miles traveled string and displaying it inside the message box;

private void button2_Click(object sender, EventArgs e) 
{
    //
    // Programmatically call the Calculate button to determine the 
    // Mileage Reimbursement Amount to ensure the Miles Traveled
    // reflects the correct value.
    //
    button1.PerformClick();
    MessageBox.Show(milesTraveled + " miles", "Miles Traveled"); 
}


I hope this was of help and interest.
0

#4 User is offline   AndrewStellman 

  • Andrew Stellman
  • PipPipPipPipPipPipPipPipPipPipPip
  • Group: O'Reilly Author
  • Posts: 749
  • Joined: 08-October 08
  • Gender:Male
  • Location:Brooklyn, NY
  • Interests:Author of: "Head First C#", "Beautiful Teams", "Head First PMP", "Applied Software Project Management"

Posted 23 February 2014 - 07:56 AM

ClockEndGooner -- wow, that was a really thorough and complete answer. Thanks for posting it! :)

In case you want a short version:

#1. You need to cast numericUpDown1.Value to an int because the NumericUpDown control uses double values, and you need to cast them to ints in order to store them in an int variable like startingMileage. The (int) in the code sample is converting that value:

startingMileage = (int) numericUpDown1.Value;


Try removing the "(int)" from that line. If your code is typed in correctly, then removing the (int) will cause the build to fail with an error like this: "Cannot implicitly convert type 'decimal' to 'int'. An explicit conversion exists (are you missing a cast?)"


#2. Make sure your code matches the solution in the book. If you have something different that doesn't use (int) in exactly the same way as the solution, the behavior won't match.


#3. Yes, that's what's supposed to happen. The annotation pointing to the Display Miles button says to click the button after you've clicked Calculate. The milesTraveled field only gets updated when you click Calculate, so if you don't click it again the milesTraveled field won't get updated, and the Display Miles button will keep displaying it.


Take the time to really figure out what's going on here, and make sure you understand it. It will help you going forward.

I hope this helps!
Andrew Stellman
Author, Head First C#
Building Better Software -- http://www.stellman-greene.com
0

#5 User is offline   Gildren 

  • Active Member
  • PipPip
  • Group: Members
  • Posts: 13
  • Joined: 20-September 13

Posted 24 February 2014 - 12:36 PM

View PostClockEndGooner, on 22 February 2014 - 08:41 PM, said:

Hi, Gildern;

In response to your first of three issues with the Mileage Calculator, I hope the following is of help and interest to you.

C# is a strongly type language, meaning that in order for your code to execute in a consistent, reliable and robust manner, with as few, if any errors, as possible, working with value data type variables must be of the same type. The milage calculator form uses the Windows Forms NumericUpDown control, which returns the current numeric value in the control as a decimal value, not as an integer, or int. If you tried assigning the value, let's say, from the startingMilage, you would receive a compile time error message from the C# compiler, CSC.Exe, along the lines of "Cannot implicitly convert type 'decimal' to 'int'. An explicit conversion exists (are you missing a cast?)", and your source code will not be able to generate an .Exe file you can run.

The casting operation (int):

startingMileage = (int) numericUpDown1.Value;


is your way of telling the C# compiler that you want your code to intentionally assign a numeric value from a larger numeric value data type, a decimal as returned by the numericUpDown1.Value, to a smaller data type, an int (Integer, or Int32, a 32-bit integer value). Since you're being explicit in making this call, the compiler will oblige and try to convert a potentially larger numeric value stored in a decimal data type to the smaller int data type.

Hopefully, the following code fragments below might help illustrate this in a clearer way;

string trace = string.Format("int.MinValue = {0}", int.MinValue.ToString());
Console.Out.WriteLine(trace);
// Output: int.MinValue = -2147483648

trace = string.Format("int.MaxValue = {0}", int.MaxValue.ToString());
Console.Out.WriteLine(trace);
// Output: int.MaxValue = 2147483647

trace = string.Format("decimal.MinValue = {0}", decimal.MinValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimal.MinValue = -79228162514264337593543950335

trace = string.Format("decimal.MaxValue = {0}", decimal.MaxValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimal.MaxValue = 79228162514264337593543950335

decimal decimalValue = 2147500000;
trace = string.Format("decimalValue = {0}", decimalValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimalValue = 21475000

trace = 
string.Format("Difference between decimalValue and int.MaxValue = {0}",
			  ((decimal) decimalValue - int.MaxValue).ToString());
Console.Out.WriteLine(trace);
// Output: Difference between decimalValue and int.MaxValue = 16353
// This means that in the .NET Runtime support for decimal and int numeric
// data types, the current decimal value is 16,353 greater than the largest 
// positive value int value an integer value, such as staringMileage or
// endingMileage can hold.

int startingMilage = decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);
// No Output: Compiler error "Cannot implicitly 
// convert type 'decimal' to 'int'. An explicit conversion 
// exists (are you missing a cast?)" is emitted by the C# 
// Compiler and should be displayed for the source code line
// in the Errors tab and pane inside Visual Studio, and in
// the Build section of the Output pane inside Visual Studio

startingMilage = (int) decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);

// Code compiles, CSC.Exe generates the .Exe file, but a special type
// of System.Exception derived class, an OverflowException is thrown
// with the following error message: "Value was either too large or 
// too small for an Int32".  The C# compiler can't check to see if 
// the assignment from a larger decimal value to a smaller integer 
// value can take place without error, but the .NET Runtime can and 
// does.  Since this is an "exceptional" or out of the ordinary error,
// the .NET Runtime environment, which executes your program, will let 
// you know of this error by theoring an OverflowException.  I think this
// is the equivalent of trying to pour a keg of beer in a one pint glass, 
// and the .NET Runtime is letting you know there's too much beer being 
// spilled and going to waste.

decimalValue = (decimal) int.MaxValue;
trace = string.Format("decimalValue = {0}", decimalValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimalValue = 2147483647

//
// If the value in decimalValue is reduced to a value that is in
// the supported range or size of the int value, the .NET Runtime
// can automatically convert and adjust the value as needed as
// it's being stored and assigned in the startingMilage variable.
//
trace = 
string.Format("decimalValue <= int.MaxValue: {0} [{1}]",
    (decimalValue <= int.MaxValue).ToString(),
    (decimalValue <= int.MaxValue) ? "Yes" : "No");
Console.Out.WriteLine(trace);
// Output: decimalValue <= int.MaxValue: True [Yes]

startingMilage = (int) decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);
// Output: startingMilage = 2147483647

trace = 
string.Format("startingMilage == (int) decimalValue: {0} [{1}]",
    (startingMilage == (int) decimalValue).ToString(),
    (startingMilage == (int) decimalValue) ? "Yes" : "No");
Console.Out.WriteLine(trace);			  
// Output: startingMilage == (int) decimalValue: True [Yes]


If you're still wondering about casting values when assigning from one data value type to a different value data type, you might want to take a look at Chapter 4's section "Casting Call". Andrew and Jennifer do a far better job at explaining this than I can.

0

#6 User is offline   Gildren 

  • Active Member
  • PipPip
  • Group: Members
  • Posts: 13
  • Joined: 20-September 13

Posted 24 February 2014 - 12:40 PM

View PostClockEndGooner, on 22 February 2014 - 08:41 PM, said:

Hi, Gildern;

In response to your first of three issues with the Mileage Calculator, I hope the following is of help and interest to you.

C# is a strongly type language, meaning that in order for your code to execute in a consistent, reliable and robust manner, with as few, if any errors, as possible, working with value data type variables must be of the same type. The milage calculator form uses the Windows Forms NumericUpDown control, which returns the current numeric value in the control as a decimal value, not as an integer, or int. If you tried assigning the value, let's say, from the startingMilage, you would receive a compile time error message from the C# compiler, CSC.Exe, along the lines of "Cannot implicitly convert type 'decimal' to 'int'. An explicit conversion exists (are you missing a cast?)", and your source code will not be able to generate an .Exe file you can run.

The casting operation (int):

startingMileage = (int) numericUpDown1.Value;


is your way of telling the C# compiler that you want your code to intentionally assign a numeric value from a larger numeric value data type, a decimal as returned by the numericUpDown1.Value, to a smaller data type, an int (Integer, or Int32, a 32-bit integer value). Since you're being explicit in making this call, the compiler will oblige and try to convert a potentially larger numeric value stored in a decimal data type to the smaller int data type.

Hopefully, the following code fragments below might help illustrate this in a clearer way;

string trace = string.Format("int.MinValue = {0}", int.MinValue.ToString());
Console.Out.WriteLine(trace);
// Output: int.MinValue = -2147483648

trace = string.Format("int.MaxValue = {0}", int.MaxValue.ToString());
Console.Out.WriteLine(trace);
// Output: int.MaxValue = 2147483647

trace = string.Format("decimal.MinValue = {0}", decimal.MinValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimal.MinValue = -79228162514264337593543950335

trace = string.Format("decimal.MaxValue = {0}", decimal.MaxValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimal.MaxValue = 79228162514264337593543950335

decimal decimalValue = 2147500000;
trace = string.Format("decimalValue = {0}", decimalValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimalValue = 21475000

trace = 
string.Format("Difference between decimalValue and int.MaxValue = {0}",
			  ((decimal) decimalValue - int.MaxValue).ToString());
Console.Out.WriteLine(trace);
// Output: Difference between decimalValue and int.MaxValue = 16353
// This means that in the .NET Runtime support for decimal and int numeric
// data types, the current decimal value is 16,353 greater than the largest 
// positive value int value an integer value, such as staringMileage or
// endingMileage can hold.

int startingMilage = decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);
// No Output: Compiler error "Cannot implicitly 
// convert type 'decimal' to 'int'. An explicit conversion 
// exists (are you missing a cast?)" is emitted by the C# 
// Compiler and should be displayed for the source code line
// in the Errors tab and pane inside Visual Studio, and in
// the Build section of the Output pane inside Visual Studio

startingMilage = (int) decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);

// Code compiles, CSC.Exe generates the .Exe file, but a special type
// of System.Exception derived class, an OverflowException is thrown
// with the following error message: "Value was either too large or 
// too small for an Int32".  The C# compiler can't check to see if 
// the assignment from a larger decimal value to a smaller integer 
// value can take place without error, but the .NET Runtime can and 
// does.  Since this is an "exceptional" or out of the ordinary error,
// the .NET Runtime environment, which executes your program, will let 
// you know of this error by theoring an OverflowException.  I think this
// is the equivalent of trying to pour a keg of beer in a one pint glass, 
// and the .NET Runtime is letting you know there's too much beer being 
// spilled and going to waste.

decimalValue = (decimal) int.MaxValue;
trace = string.Format("decimalValue = {0}", decimalValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimalValue = 2147483647

//
// If the value in decimalValue is reduced to a value that is in
// the supported range or size of the int value, the .NET Runtime
// can automatically convert and adjust the value as needed as
// it's being stored and assigned in the startingMilage variable.
//
trace = 
string.Format("decimalValue <= int.MaxValue: {0} [{1}]",
    (decimalValue <= int.MaxValue).ToString(),
    (decimalValue <= int.MaxValue) ? "Yes" : "No");
Console.Out.WriteLine(trace);
// Output: decimalValue <= int.MaxValue: True [Yes]

startingMilage = (int) decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);
// Output: startingMilage = 2147483647

trace = 
string.Format("startingMilage == (int) decimalValue: {0} [{1}]",
    (startingMilage == (int) decimalValue).ToString(),
    (startingMilage == (int) decimalValue) ? "Yes" : "No");
Console.Out.WriteLine(trace);			  
// Output: startingMilage == (int) decimalValue: True [Yes]


If you're still wondering about casting values when assigning from one data value type to a different value data type, you might want to take a look at Chapter 4's section "Casting Call". Andrew and Jennifer do a far better job at explaining this than I can.


I think I get it. I didn't realize the numberic up/down field had a native decimal format -- I always thought it went up and down by whole numbers, so I didn't occur to me I had to cast it as whole numbers. Good to know. Thanks.
0

#7 User is offline   Gildren 

  • Active Member
  • PipPip
  • Group: Members
  • Posts: 13
  • Joined: 20-September 13

Posted 24 February 2014 - 12:43 PM

View PostClockEndGooner, on 22 February 2014 - 08:41 PM, said:

Hi, Gildern;

In response to your first of three issues with the Mileage Calculator, I hope the following is of help and interest to you.

C# is a strongly type language, meaning that in order for your code to execute in a consistent, reliable and robust manner, with as few, if any errors, as possible, working with value data type variables must be of the same type. The milage calculator form uses the Windows Forms NumericUpDown control, which returns the current numeric value in the control as a decimal value, not as an integer, or int. If you tried assigning the value, let's say, from the startingMilage, you would receive a compile time error message from the C# compiler, CSC.Exe, along the lines of "Cannot implicitly convert type 'decimal' to 'int'. An explicit conversion exists (are you missing a cast?)", and your source code will not be able to generate an .Exe file you can run.

The casting operation (int):

startingMileage = (int) numericUpDown1.Value;


is your way of telling the C# compiler that you want your code to intentionally assign a numeric value from a larger numeric value data type, a decimal as returned by the numericUpDown1.Value, to a smaller data type, an int (Integer, or Int32, a 32-bit integer value). Since you're being explicit in making this call, the compiler will oblige and try to convert a potentially larger numeric value stored in a decimal data type to the smaller int data type.

Hopefully, the following code fragments below might help illustrate this in a clearer way;

string trace = string.Format("int.MinValue = {0}", int.MinValue.ToString());
Console.Out.WriteLine(trace);
// Output: int.MinValue = -2147483648

trace = string.Format("int.MaxValue = {0}", int.MaxValue.ToString());
Console.Out.WriteLine(trace);
// Output: int.MaxValue = 2147483647

trace = string.Format("decimal.MinValue = {0}", decimal.MinValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimal.MinValue = -79228162514264337593543950335

trace = string.Format("decimal.MaxValue = {0}", decimal.MaxValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimal.MaxValue = 79228162514264337593543950335

decimal decimalValue = 2147500000;
trace = string.Format("decimalValue = {0}", decimalValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimalValue = 21475000

trace = 
string.Format("Difference between decimalValue and int.MaxValue = {0}",
			  ((decimal) decimalValue - int.MaxValue).ToString());
Console.Out.WriteLine(trace);
// Output: Difference between decimalValue and int.MaxValue = 16353
// This means that in the .NET Runtime support for decimal and int numeric
// data types, the current decimal value is 16,353 greater than the largest 
// positive value int value an integer value, such as staringMileage or
// endingMileage can hold.

int startingMilage = decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);
// No Output: Compiler error "Cannot implicitly 
// convert type 'decimal' to 'int'. An explicit conversion 
// exists (are you missing a cast?)" is emitted by the C# 
// Compiler and should be displayed for the source code line
// in the Errors tab and pane inside Visual Studio, and in
// the Build section of the Output pane inside Visual Studio

startingMilage = (int) decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);

// Code compiles, CSC.Exe generates the .Exe file, but a special type
// of System.Exception derived class, an OverflowException is thrown
// with the following error message: "Value was either too large or 
// too small for an Int32".  The C# compiler can't check to see if 
// the assignment from a larger decimal value to a smaller integer 
// value can take place without error, but the .NET Runtime can and 
// does.  Since this is an "exceptional" or out of the ordinary error,
// the .NET Runtime environment, which executes your program, will let 
// you know of this error by theoring an OverflowException.  I think this
// is the equivalent of trying to pour a keg of beer in a one pint glass, 
// and the .NET Runtime is letting you know there's too much beer being 
// spilled and going to waste.

decimalValue = (decimal) int.MaxValue;
trace = string.Format("decimalValue = {0}", decimalValue.ToString());
Console.Out.WriteLine(trace);
// Output: decimalValue = 2147483647

//
// If the value in decimalValue is reduced to a value that is in
// the supported range or size of the int value, the .NET Runtime
// can automatically convert and adjust the value as needed as
// it's being stored and assigned in the startingMilage variable.
//
trace = 
string.Format("decimalValue <= int.MaxValue: {0} [{1}]",
    (decimalValue <= int.MaxValue).ToString(),
    (decimalValue <= int.MaxValue) ? "Yes" : "No");
Console.Out.WriteLine(trace);
// Output: decimalValue <= int.MaxValue: True [Yes]

startingMilage = (int) decimalValue;
trace = string.Format("startingMilage = {0}", startingMilage.ToString());
Console.Out.WriteLine(trace);
// Output: startingMilage = 2147483647

trace = 
string.Format("startingMilage == (int) decimalValue: {0} [{1}]",
    (startingMilage == (int) decimalValue).ToString(),
    (startingMilage == (int) decimalValue) ? "Yes" : "No");
Console.Out.WriteLine(trace);			  
// Output: startingMilage == (int) decimalValue: True [Yes]


If you're still wondering about casting values when assigning from one data value type to a different value data type, you might want to take a look at Chapter 4's section "Casting Call". Andrew and Jennifer do a far better job at explaining this than I can.


I think I understand. I didn't think the numeric up/down field was in decimal format -- I thought it was only whole numbers, so I didn't occur to me that I needed to cast it. Thanks.
0

#8 User is offline   Gildren 

  • Active Member
  • PipPip
  • Group: Members
  • Posts: 13
  • Joined: 20-September 13

Posted 24 February 2014 - 01:25 PM

View PostAndrewStellman, on 23 February 2014 - 07:56 AM, said:

ClockEndGooner -- wow, that was a really thorough and complete answer. Thanks for posting it! :)

In case you want a short version:

#1. You need to cast numericUpDown1.Value to an int because the NumericUpDown control uses double values, and you need to cast them to ints in order to store them in an int variable like startingMileage. The (int) in the code sample is converting that value:

startingMileage = (int) numericUpDown1.Value;


Try removing the "(int)" from that line. If your code is typed in correctly, then removing the (int) will cause the build to fail with an error like this: "Cannot implicitly convert type 'decimal' to 'int'. An explicit conversion exists (are you missing a cast?)"

Ah, I didn't realize that the numeric Up/Down field was "double" (and not "decimal" like I previously thought). That makes more sense.


#2. Make sure your code matches the solution in the book. If you have something different that doesn't use (int) in exactly the same way as the solution, the behavior won't match.


The only thing radically different was I put
if (endingMileage >= startingMileage)
which shouldn't have effected it at all. Not sure why it did that, but it's probably not important.



#3. Yes, that's what's supposed to happen. The annotation pointing to the Display Miles button says to click the button after you've clicked Calculate. The milesTraveled field only gets updated when you click Calculate, so if you don't click it again the milesTraveled field won't get updated, and the Display Miles button will keep displaying it.

That's fine. If this app was for a real audience thought, I'd think we'd want both buttons to work independently, or it would confuse them. However, for this exercise it makes sense.


Take the time to really figure out what's going on here, and make sure you understand it. It will help you going forward.

Thanks for the clarifications. They help a lot!

I hope this helps!

0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users