Statements, Keywords, Scope, Types, Variables, and Conversions
AAHC

Click on A to make all fonts on the page smaller.

Click on A to make all fonts on the page larger.

Click on HC to toggle high contrast mode. When you move your mouse over some bold words in high contrast mode, related words are automatically highlighted. Text is shown in black and white.


In the first course, the emphasis was on moving through a lot of basic material to get up and running quickly. This second course will again emphasize hands-on programming, but will be adding more depth to your experience with the C# language and the Visual Studio IDE.

In this lesson, we will learn more about the syntax, data types, and variables used with C#.

As with the first course, we encourage you to type in all sample code, as well as experiment on your own!

Programming Statements

Previously, we've seen numerous programming statements. For the purpose of this course, programming statements are like sentences in a spoken language, composed of elements of the programming language to represent the smallest valid unit. The following are examples of simple programming statements in C#:

You can also use compound programming statements:

We construct programming statements from the building blocks of the programming language. These building blocks consist of reserved keywords (which, as we've mentioned, may not be used as identifier names) and identifiers (classes, methods, variables) assembled using the C# language syntax.

Identifiers and Reserved Words

The concept of programming statements, identifiers, reserved words, and language syntax should be familiar to you from the first course. You've used quite a few of the C# reserved words already, such as class, if, else, for, int, string, and so on. Microsoft provides a complete list of reserved words used with the C# language and Visual Studio 2010 here:

Visual Studio 2010 C# Keywords

We've defined the rules for a C# variable earlier, but we'll repeat those rules here as they apply to all identifiers (classes, methods, and variables):

Note Feel free to investigate some of the keywords you're familiar with, and others you're not familiar with. Also, you may note a second table of keywords referred to as "Contextual Keywords." We'll discuss these keywords later, as we cover material related to them.

Scope
Scope Definition

Remember all of those curly braces ({ and }) we used in our programs? They are part of an important concept known as scope. Just as we use a microscope to reveal things we may not be able to see without assistance, programming scope refers to the visibility of the variables, classes, objects, and methods throughout our software. Let's create a new project to explore the concepts of scope, including the use of braces.

Local Scope

Select File | New | Project. In the New Project dialog box, change the Name of the project to SimpleScope, All other dropdowns and checkboxes should have their default settings:

Click OK. Your new Windows Form Application appears.

Locate and click on the entry for Form1.cs and replace the highlighted text with SimpleScope.cs.

Click on the Form1 Form title bar, and find the Text property in the Property Window. Change the Text property from Form1 to Simple Scope:

 

Drag a ListBox control from the Toolbox onto your form, and resize the ListBox to take up most of the space in the form:

Click the new ListBox control, and in the Properties Window, change the Name property to scopeListBox.

This is a good time to click .

Next, we'll add code to our project, so we'll need to view the Code Editor for the Form.

Right-click the SimpleScope.cs Form entry in the Solution Explorer, and select View Code:

You should see the default Windows Form code for your project in the Code Editor:

Now, let's add our C# code to explore the concept of scope.

Modify the SimpleScope.cs code as shown below to add the decision-making code:

SimpleScope.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SimpleScope
{
    public partial class SimpleScope : Form
    {
        public SimpleScope()
        {
            InitializeComponent();
            
            // Scope variables
            int numberToSquare = 3;
            int squaredResult = 0;
            
            // Call square method and document values.
            scopeListBox.Items.Add("Number value BEFORE method call: " + numberToSquare);
            squaredResult = square(numberToSquare);
            scopeListBox.Items.Add("Number value AFTER method call: " + numberToSquare);
            scopeListBox.Items.Add("Result: " + squaredResult);
        }

        private int square(int numberToSquare)
        {
            numberToSquare = 5;
            return (numberToSquare * numberToSquare);
        }
    }
}        

and to run the program. You should see this:

As you can see, the value of numberToSquare remains the same before and after the call to the square() method, but inside the method, the numberToSquare value assignment worked, as the result of the method call is the square of 5, or 25.

Let's discuss how this code works. As we did in the first course, we'll omit the code that doesn't concern us.

OBSERVE: SimpleScope.cs
.
.
.
        public SimpleScope()
        {
            InitializeComponent();
            
            // Scope variables
            int numberToSquare = 3;
            int squaredResult = 0;
            
            // Call square method and document values
            scopeListBox.Items.Add("Number value BEFORE method call: " + numberToSquare);
            squaredResult = square(numberToSquare);
            scopeListBox.Items.Add("Number value AFTER method call: " + numberToSquare);
            scopeListBox.Items.Add("Result: " + squaredResult);
        }
    
        private int square(int numberToSquare)
        {
            numberToSquare = 5;
            return (numberToSquare * numberToSquare);
        }
.
.
.

Examine the use of the variable numberToSquare/numberToSquare. Yes, they are two different variables. numberToSquare is used in the SimpleScope method, and numberToSquare is a method parameter or argument to the square method. Consider these questions:

  • Are these two variables really the same variable, perhaps because they both have the same name?
  • Is the value of numberToSquare the same before and after the call to square?
  • What happens to numberToSquare after the call to square?

As you consider these questions, recognize that what we're really asking about is scope. Does a variable declared within one method become the same variable in another method if both variables have the same name as in our code? The answer is No. The scope, or visibility, of a variable is determined by where the variable is declared. A variable declared within a method is said to have local scope. Once that method has been executed, any local variables, including method parameters and arguments, no longer exist. So what are the answers to the scope questions?

  • The two numberToSquare variables are not the same, as each exists within its own local scope.
  • The value of numberToSquare remains the same, even if you changed numberToSquare within the square method.
  • Once the square method exits, numberToSquare no longer exists.
Block Scope

Within a method, you can have additional levels of scope known as block scope. This level of scope is created whenever you use those pernicious {braces}! That means if you use C# keywords like if(), you're creating a block! Let's try that.

Modify the SimpleScope.cs code as shown below.

SimpleScope.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SimpleScope
{
    public partial class SimpleScope : Form
    {
        public SimpleScope()
        {
            InitializeComponent();
            
            // Scope variables
            int numberToSquare = 3;
            int squaredResult = 0;
            
            // Call square method and document values
            scopeListBox.Items.Add("Number value BEFORE method call: " + numberToSquare);
            squaredResult = square(numberToSquare);
            scopeListBox.Items.Add("Number value AFTER method call: " + numberToSquare);
            scopeListBox.Items.Add("Result: " + squaredResult);
            
            // Block scope
            if (1 > 0) 
            {
                int firstBlockTest = 10;
            }
            squaredResult = square(firstBlockTest);
            scopeListBox.Items.Add("Result after block: " + squaredResult);
        }
        
        private int square(int numberToSquare)
        {
            numberToSquare = 5;
            return (numberToSquare * numberToSquare);
        }
    }
}

After adding the block code, you'll see a squiggly red error line under the firstBlockTest variable. If you hover your mouse pointer over the error, you will see a popup message that indicates the variable "firstBlockTest" does not exist in the current context:

But we initialized firstBlockTest to 10 just a couple of lines earlier! What does this error mean? It means that the variable firstBlockTest, even though it was declared within the block if() scope, is no longer valid because the variable has gone out of scope. Variables are often referred to as in scope or out of scope, to indicate whether or not the variable exists and is visible to the current scope. Let's fix the code so we can use the firstBlockTest variable.

Note Previously, we saw that you do not have to use braces with the if() syntax if you only have a single line, although we've encouraged you to be consistent and include the braces in all cases. When using a single-line if() block without braces in C#, you cannot declare a new variable. You must use braces if you want to declare new block-level variables.

Modify the SimpleScope.cs code as shown below:

SimpleScope.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SimpleScope
{
    public partial class SimpleScope : Form
    {
        public SimpleScope()
        {
            InitializeComponent();
            
            // Scope variables
            int numberToSquare = 3;
            int squaredResult = 0;
            
            // Call square method and document values
            scopeListBox.Items.Add("Number value BEFORE method call: " + numberToSquare);
            squaredResult = square(numberToSquare);
            scopeListBox.Items.Add("Number value AFTER method call: " + numberToSquare);
            scopeListBox.Items.Add("Result: " + squaredResult);
            
            // Block scope
            int firstBlockTest = 0;
            if (1 > 0) 
            {
                int firstBlockTest = 10;
            }
            squaredResult = square(firstBlockTest);
            scopeListBox.Items.Add("Result after block: " + squaredResult);
        }
        
        private int square(int numberToSquare)
        {
            return (numberToSquare * numberToSquare);
        }
    }
}

and to run the program. You should see this:

Let's discuss how this code works.

OBSERVE: SimpleScope.cs
.
.
.
            
            // Block scope
            int firstBlockTest = 0;
            if (1 > 0) 
            {
              firstBlockTest = 10;
            }
            squaredResult = square(firstBlockTest);
            scopeListBox.Items.Add("Result after block: " + squaredResult);
.
.
.

Because the variable firstBlockTest is now declared outside the if block, its scope is broadened; within the braces block, we're simply changing its value. You should note that you may not have a block scope variable with the same name as a local scope variable.

NoteAlthough the technique is rarely used, you can create a block scope simply by using braces! Go ahead, try it!

Class Scope

In previous lessons, we've seen that we can declare variables that serve as properties for our class. These class variables have class scope, and are visible to all of the methods within the class in which they are declared. Unlike with local and block scope variables, you are allowed to have a class scope variable with the same name as a local or block scope variable; however, a local or block scope variable takes precedence and will be used over the class scope variable! We'll learn in a later lesson how to select the correct variable when a class and local variable have the same name.

Let's add a class-level variable.

Modify SimpleScope.cs as shown below.

SimpleScope.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SimpleScope
{
    public partial class SimpleScope : Form
    {
        private int myClassVariable = 25;
    
        public SimpleScope()
        {
            InitializeComponent();
            
            // Scope variables
            int numberToSquare = 3;
            int squaredResult = 0;
            
            // Call square method and document values
            scopeListBox.Items.Add("Number value BEFORE method call: " + numberToSquare);
            squaredResult = square(numberToSquare);
            scopeListBox.Items.Add("Number value AFTER method call: " + numberToSquare);
            scopeListBox.Items.Add("Result: " + squaredResult);
            
            // Block scope
            int firstBlockTest = 0;
            if (1 > 0) 
            {
                firstBlockTest = 10;
                firstBlockTest = 10;
            }
            squaredResult = square(firstBlockTest);
            scopeListBox.Items.Add("Result after block: " + squaredResult);
            
            // Use class scope variable.
            scopeListBox.Items.Add("Class variable result: " + square(myClassVariable));
        }
            
        private int square(int numberToSquare)
        {
            return (numberToSquare * numberToSquare);
        }
    }
}

and to run the program. You should see this:

Let's discuss how this code works.

OBSERVE: SimpleScope.cs
.
.
.
namespace SimpleScope
{
    public partial class SimpleScope : Form
    {
        private int myClassVariable = 25;
        
        public SimpleScope()
        {
.
.
.
            // Use class scope variable
            scopeListBox.Items.Add("Class variable result: " + square(myClassVariable));
        }
    
        private int square(int numberToSquare)
        {
            return (numberToSquare * numberToSquare);
        }
    }
.
.
.

The class variable myClassVariable is declared outside of any method, at the class scope. We use the variable in our call to square and output the results. As you can see from the code, we did not need to declare myClassVariable within the local scope to use the variable.

Scope Importance

We've discovered the differences between local, block, and class scope, but why is scope so important? Why not just declare all variables at the class level? Variables in general are what we use to hold information as our programs perform the tasks we've programmed THEM to perform, so ensuring our variables only have the data and values we require is very important for data integrity. As we implement an object-oriented approach to software development, we want to employ the concept of information hiding: limiting access to data and variables to only those parts of our program, and other software, that needs access. Variables require memory, so we should limit class variables to reduce a program's memory requirements, and use local variables that effectively use memory only temporarily. Finally, declaring and using variables in close proximity to where they are used, such as within a block, makes implementing, understanding, and later deciphering a program a simpler task.

Data Types
Built-In Types

We've used a number of different data types so far, such as bool, int, double, float, long, and string. These are just some of the data types available in C#. Here's a complete list of available data types (note table below as well):

Visual Studio 2010 C# Data Types

As with reserved words, we'll continue to explore the data types as we work through these lessons, but feel free to click on any of the data types and read more about what they represent. One common topic related to data types is the amount of computer memory they use, and the ranges of values they can contain. Below are all data types, their ranges of values, the amount of memory they use, a reference to the underlying .NET data type, and a column about precision, if applicable.

TypeRangeSize.NET Framework TypePrecision
booltrue, falseUnsigned 8-bit integerSystem.Boolean 
sbyte-128 to 127Signed 8-bit integerSystem.SByte 
short-32,768 to 32,767Signed 16-bit integerSystem.Int16 
int-2,147,483,648 to 2,147,483,647Signed 32-bit integerSystem.Int32 
long–9,223,372,036,854,775,808 to 9,223,372,036,854,775,807Signed 64-bit integerSystem.Int64 
float±1.5 x 10-45 to ±3.4 x 1038Signed 32-bit integerSystem.Single7 digits
double±5.0 x 10-324 to ±1.7 x 10308Signed 64-bit integerSystem.Double15-16 digits
decimal(-7.9 x 1028 to 7.9 x 1028) / (100 to 28)Signed 128-bit integerSystem.Decimal28-29 significant digits
byte0 to 255Unsigned 8-bit integerSystem.Byte 
ushort0 to 65,535Unsigned 16-bit integerSystem.UInt16 
uint0 to 4,294,967,295Unsigned 32-bit integerSystem.UInt32 
ulong0 to 18,446,744,073,709,551,615Unsigned 64-bit integerSystem.UInt64 
charU+0000 to U+FFFFUnicode 16-bit characterSystem.Char 
stringCharacter dataOperating system dependantSystem.String 
objectObject dataOperating system dependentSystem.Object 

You'll notice that the table contains some familiar data types and unfamiliar data types. There are a number of integer data types, or numbers that do not have any decimal value: sbyte, short, int, and long. There are data types that have decimal places: float, double, and decimal. There is the familiar boolean data type bool. There are data types that are like integers, but must be the value 0 or higher (non-negative): byte, ushort, uint, and ulong. There is the string data type we've used, and another called char that only allows a single character. And, finally, there is the object data type, which is the parent data type that all predefined and user-defined data types inherit.

Note As C# is but one programming language supported by the .NET framework, and as with all other .NET-based languages, all data types used in C# represent an underlying .NET data type. The .NET Framework Type column indicates the actual underlying .NET data type. They are interchangeable; you can use the C# or the .NET data type in your C# programs. For consistency, we recommend you stick with the C# data type names.

Let's experiment more with the different data types.

Selecting File | New | Project. In the New Project dialog box, change the Name to MoreVariableFun; all other dropdowns and checkboxes should have their default settings. Click OK.

The new Windows Form Application appears.

Locate and click the entry for Form1.cs and replace it with MoreVariableFun.cs. Click to save your changes.

Next, let's add an sbyte and SByte to our code, and see what Intellisense tells us about this smallest of integer data types.

Modify MoreVariableFun.cs as shown below:

MoreVariableFun.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MoreVariableFun
{
    public partial class MoreVariableFun : Form
    {
        public MoreVariableFun()
        {
            InitializeComponent();
            
            // Fun with integers.
            sbyte firstVariable = 1;
            SByte secondVariable = firstVariable;
        }
    }
}

As we mentioned, sbyte and SByte (System.SByte) are synonymous in C#. You should use the C# sbyte data type rather than the .NET underlying variable data type, but this example illustrates that you can use them interchangeably. The code also illustrates that—as you would expect with compatible data types—you can assign the value of one variable, firstVariable, to another of the same data type, secondVariable.

MoreVariableFun.cs
.
.
.
            InitializeComponent();
            
            // Fun with integers.
            sbyte firstVariable = 1;
            SByte secondVariable = firstVariable;
.
.
.

Further, if you hover your mouse pointer over either sbyte or SByte, you'll see the same Intellisense popup:

Two key differences with numeric data types are the range of the data type, and the amount of memory needed to hold a variable declared as that specific data type. You must be aware of the data type range, or you will experience what is known as overflow, which means you have attempted to store a number that exceeds the capacity of the data type you've chosen—much like pouring 14 ounces of water into a 12-ounce container.

Let's see what happens if we try to set one of the variables to a value larger than it can hold. For sbyte, according to our table, the range is -127 to 127.

Modify MoreVariableFun.cs as shown:

Note Remember, you can hide or display different sections of your source code to make it easier to view using the plus or minus symbol that appears to the left of the first line in the section. Here, we're hiding the using section.

MoreVariableFun.cs
using ...

namespace MoreVariableFun
{
    public partial class MoreVariableFun : Form
    {
        public MoreVariableFun()
        {
            InitializeComponent();
            
            // Fun with integers.
            sbyte firstVariable = 1128;
            SByte secondVariable = firstVariable;
        
        }
    }
}

As soon as you change the assignment from 1 to 128, you will see the red squiggly error line under the 128. Hover your mouse pointer over the 128 and note the popup error box indicating that you can't assign 128 to sbyte, which is what you'd expect from the range of values for an sbyte from the table:

Note You might think that you should try to use the smallest possible data type based on the range of the number you might use, but in general, when declaring method level variables, you should use data types that are divisible by 32, as these numbers store more efficiently in memory, and process faster through the computer processor. So, for an integer, you should use int or long. For numbers with decimal places, you can use float, although the default numeric value in C# is double, so using double data types is more common.

Let's change the code again to allow this larger value by using integer data types that allow a much larger range of values. From our table, the next larger integer data type is short, then int, and, finally, long.

Modify MoreVariableFun.cs as shown below.

MoreVariableFun.cs
using ...

namespace MoreVariableFun
{
    public partial class MoreVariableFun : Form
    {
        public MoreVariableFun()
        {
            InitializeComponent();
            
            // Fun with integers.
            sbyteshort firstVariable = 128;
            SByteint secondVariable = firstVariable;
        }
    }
}

Remember to periodically!

As you can see, we changed the sbyte to short, and SByte to int. Remember, you can almost always assign numeric data of a smaller data type to variables of a larger data type. This process is called widening, which we've discussed before, and is always possible when the resulting assignment will not result in a loss of data. In fact, the short data type is promoted using implicit casting during the assignment from a short to an int. C# uses implicit casting whenever necessary to allow assignment where no data loss will occur. In instances where implicit conversion is not allowed, Visual Studio will indicate that fact with an error.

NoteWhat does signed and unsigned mean? We've previously indicated that unsigned means the data type can only store values that are greater than or equal to 0, but from a memory point of view, you'll notice that unsigned data types have a slightly larger range than their equivalent signed data types. The reason is that unsigned data types do not have to store the sign, and have more storage space to increase their range. The same recommendation applies when using unsigned data types: use a data type that is divisible by 32.

In our table, for float, double, and decimal types, the Precision column indicates an important point about numbers with decimal places, also known as precision. These three data types are not identical. Float and double are both floating-point data types, which means that as the number gets larger, the decimal point floats, and the large number is represented using scientific, or exponential, notation. For most calculations, using a floating point data type is sufficient, but if you need to control the precision more precisely, for example with scientific calculations or currency, you should use decimal. The significant digits refers to precision, which can be fixed and maintained in decimal, but may be lost in the floating point data types.

Let's work with these data types as well.

Modify MoreVariableFun.cs as shown below.

MoreVariableFun.cs
using ...

namespace MoreVariableFun
{
    public partial class MoreVariableFun : Form
    {
        public MoreVariableFun()
        {
            InitializeComponent();
            
            // Fun with integers.
            short firstVariable = 128;
            int secondVariable = firstVariable;
            
            // Fun with float, double, and decimal.
            float thirdVariable = 0.0;
            double fourthVariable = thirdVariable;
            decimal fifthVariable = fourthVariable;
        
        }
    }
}

More squiggly red line errors!

Hover over the squiggly red error line under the 0.0 assignment, and examine the error message.

You might remember that numeric literals in C#, by default, are doubles. Attempting to assign a double to a float could result in data loss, so Visual Studio will not allow it. The error message gives you a hint on how to fix the problem: add an F after the numeric literal 0.0 to change it from a double to a float.

Modify MoreVariableFun.cs as shown below:

MoreVariableFun.cs
using ...

namespace MoreVariableFun
{
    public partial class MoreVariableFun : Form
    {
        public MoreVariableFun()
        {
            InitializeComponent();
            
            // Fun with integers.
            short firstVariable = 128;
            int secondVariable = firstVariable;
            
            // Fun with float, double, and decimal.
            float thirdVariable = 0.00.0F;
            double fourthVariable = thirdVariable;
            decimal fifthVariable = fourthVariable;
        }
    }
}

Hover over the squiggly red error line under the fourthVariable variable and examine the error message:

This message might be puzzling—why can't a double be converted to a decimal? If we examine the table, you'll note that even though a decimal can hold a much larger range of decimal places, the range of values is much smaller, so Visual Studio doesn't allow you to implicitly cast from double to decimal. In fact, you also can't reverse the process and implicitly cast from decimal to double, as that conversion could result in a loss of precision. So, what can we do? The error message again indicates a possible solution by stating that an explicit conversion exists.

Modify MoreVariableFun.cs as shown below.

MoreVariableFun.cs
using ...

namespace MoreVariableFun
{
    public partial class MoreVariableFun : Form
    {
        public MoreVariableFun()
        {
            InitializeComponent();
            
            // Fun with integers.
            short firstVariable = 128;
            int secondVariable = firstVariable;
            
            // Fun with float, double, and decimal.
            float thirdVariable = 0.0F;
            double fourthVariable = thirdVariable;
            decimal fifthVariable = Convert.ToDecimal(fourthVariable);
        }
    }
}

That fixed the problem, and showed us a handy object we can use for conversion between different data types: Convert. As you type in Convert, then type the period, you'll notice the Intellisense dropdown providing an extensive list of conversion options:

You can use the Convert object for most of your conversion needs, and you'll see it used by many C# software developers, but, there is one slight problem with this object. What will happen if you attempt to do a conversion, but the conversion fails? Let's further modify our code to create a failed Convert scenario using the Convert.ToInt32() conversion to convert a string literal to an int.

Modify MoreVariableFun.cs as shown below.

MoreVariableFun.cs
using ...

namespace MoreVariableFun
{
    public partial class MoreVariableFun : Form
    {
        public MoreVariableFun()
        {
            InitializeComponent();
            
            // Fun with integers.
            short firstVariable = 128;
            int secondVariable = firstVariable;
            
            // Fun with float, double, and decimal.
            float thirdVariable = 0.0F;
            double fourthVariable = thirdVariable;
            decimal fifthVariable = Convert.ToDecimal(fourthVariable);
            
            // Create a failed Convert scenario.
            int seventhValue = Convert.ToInt32("1.23456");
        }
    }
}

Save your changes, and click to execute the program. An error, or exception, occurs:

So, the Convert object might not always work! We'll learn how to handle such errors later, but in the meantime we can use a different conversion method that will let us know if the conversion was successful or not, using TryParse.

Modify MoreVariableFun.cs as shown below:

MoreVariableFun.cs
using ...

namespace MoreVariableFun
{
    public partial class MoreVariableFun : Form
    {
        public MoreVariableFun()
        {
            InitializeComponent();
            
            // Fun with integers.
            short firstVariable = 128;
            int secondVariable = firstVariable;
            
            // Fun with float, double, and decimal.
            float thirdVariable = 0.0F;
            double fourthVariable = thirdVariable;
            decimal fifthVariable = Convert.ToDecimal(fourthVariable);
            
            // Create a failed Convert scenario.
            int seventhValue = Convert.ToInt32("1.23456");
            int seventhValue;
            if (int.TryParse("1.23456", out seventhValue))
                MessageBox.Show("Conversion successful!");
            else
                MessageBox.Show("Conversion did not work!");
        }
    }
}

Save your changes, and click to execute the program. You'll no longer get an exception; instead, you'll see a message box saying "Conversion did not work!".

Let's discuss how this code works.

MoreVariableFun.cs
.
.
.
            // Create a failed Convert scenario.
            int seventhValue;
            if (int.TryParse("1.23456", out seventhValue))
                MessageBox.Show("Conversion successful!");
            else
                MessageBox.Show("Conversion did not work!");
.
.
.

Each data type includes a TryParse method that works to try to convert from a data type to itself. In our case, we called on the int version of TryParse to convert the string literal "1.23456" to an int. TryParse will return a boolean—true if the conversion was successful, and false if the conversion failed—which allows us to handle either scenario. Also, if the conversion is successful, the converted value is stored in a parameter passed into the TryParse method. In our case, we used the int variable seventhValue. Note the C# keyword parameter modifier out is used. The out modifier allows us to change the value of seventhValue inside the TryParse method.

Note You may wonder which method is faster: Convert or TryParse. The winner is Convert, but only by a very, very small margin when no conversion error is detected. If an error occurs, TryParse is much slower, but such errors are indeed supposed to be rare, so, in general, using TryParse is preferred for string-to-numeric data type conversions.

To be thorough, let's add one final conversion technique using explicit casting that you may see in code, and you may use yourself. This syntax is a legacy format, and is often used to prevent any implicit casting C# may provide. This type of casting uses a data type surrounded by parentheses.

Modify MoreVariableFun.cs as shown below.

MoreVariableFun.cs
using ...

namespace MoreVariableFun
{
    public partial class MoreVariableFun : Form
    {
        public MoreVariableFun()
        {
            InitializeComponent();
            
            // Fun with integers.
            short firstVariable = 128;
            int secondVariable = firstVariable;
            
            // Fun with float, double, and decimal.
            float thirdVariable = 0.0F;
            double fourthVariable = thirdVariable;
            decimal fifthVariable = Convert.ToDecimal(fourthVariable);
            
            // Create a failed Convert scenario.
            int seventhValue;
            if (int.TryParse("1.23456", out seventhValue))
              MessageBox.Show("Conversion successful!");
            else
              MessageBox.Show("Conversion did not work!");
              
            // Force explicit casting.
            decimal eighthVariable = (decimal)fourthVariable;
        }
    }
}

Save your changes. Note that there are no squiggly lines—always a good thing!

Let's discuss how this code works.

MoreVariableFun.cs
.
.
.            // Force explicit casting.
            decimal eighthVariable = (decimal)fourthVariable;
.
.
.

This last example is the same one we used earlier with the Convert object, but this time we've prefixed the fourthVariable with (decimal), which forces the data type to be converted to a decimal. This does not guarantee a conversion, and could still result in an error, so when possible, use the TryParse method for strings, and Convert for numeric conversions.

Before you move on to the next lesson, do your homework! Right-click in the window where this lesson text appears and select Back. Then select Quiz for this lesson in the syllabus and answer the quiz questions. When you finish the quiz questions, click Hand it in at the bottom of that window. Then do the same with the Project(s) for the lesson. Your instructor will grade your quiz(zes) and project(s) and provide guidance if needed.