17 KiB
Convert data types using casting and conversion techniques
Take control of the data in your applications, knowing when to apply the correct technique to change data types as needed.
Learning objectives
Use the casting operator to cast a value into a different data type.
Use conversion methods to convert a value into a different data type.
Guard against the loss of data when performing a cast or conversion operation.
Use the TryParse()
method to safely convert a string into a numeric data type.
Introduction
Suppose you're a software developer on a team working on medical intake form
automation. You're tasked with delivery of the application features for
collecting data entered by a medical technician before the doctor sees the
patient. The technician can use the application to record the date and time,
patient age, height, weight, pulse, and blood pressure. The application also
provides text fields for other information, such as the reason for the visit,
current prescriptions, and other items. You work with many data that is in a
mix of data types. For the prototype, you'll build a console application and
collect all of the input as strings
.
Because the input is initially input as a string, you need to occasionally
change values from one data type into another in the code. A simple example is
any mathematical operation you want to perform with string data. You would
first need to change the value into a numeric data type, like int
, and then you
could manipulate the operation. Alternatively, you may want to format and
output a numeric value for a summary report using string interpolation.
You use different techniques to change a data type when necessary. You learn when to use one technique over another, and when a given technique might risk the loss of data.
By the end of this module, you're able to take control of the data in your applications, knowing when to apply the correct technique to change data types as needed.
Learning objectives
In this module, you'll:
- Use the casting operator to cast a value into a different data type.
- Use conversion methods to convert a value into a different data type.
- Guard against the loss of data when performing a cast or conversion operation.
- Use the
TryParse()
method to safely convert a string into a numeric data type.
Exercise
Explore data type casting and conversion
There are multiple techniques to perform a data type conversion. The technique you choose depends on your answer to two important questions:
- Is it possible, depending on the value, that attempting to change the value's data type would throw an exception at run time?
- Is it possible, depending on the value, that attempting to change the value's data type would result in a loss of information? In this exercise, you work your way through these questions, the implications of their answers, and which technique you should use when you need to change the data type.
Prepare your coding environment
Create a new console application. At the Terminal command prompt type:
dotnet new console -o ./path_to/Project
or dotnet new console -n "Project"
and then press Enter.
This .NET CLI command uses a .NET program template to create a new C# console application project in the specified folder location.
You use this C# console project to create, build, and run code samples during this module.
Close the Terminal panel.
Question
Is it possible that attempting to change the value's data type would throw an exception at run time?
The C# compiler attempts to accommodate your code, but doesn't compile operations that could result in an exception. When you understand the C# compiler's primary concern, understanding why it functions a certain way is easier.
Write code that attempts to add an int
and a string
and save the result in an int
Type the following code into the Visual Studio Code Editor:
int first = 2;
string second = "4";
int result = first + second;
Console.WriteLine(result);
Here, you're attempting to add the values 2
and 4
. The value 4
is of type
string
. Will this work?
At the Terminal command prompt, to run your code, type dotnet run
and then
press Enter.
You should see the following approximate output
Windows:
C:\Users\someuser\Documents\csharpprojects\TestProject\Program.cs(3,14): error CS0029: Cannot implicitly convert type 'string' to 'int'
Linux:
/home/user/Projects/TestProject/Program.cs(3,14): error CS0029: Cannot implicitly convert type 'string' to 'int'
Note
If you see a message saying "Couldn't find a project to run", ensure that the Terminal command prompt displays the expected TestProject folder location. For example:C:\Users\someuser\Documents\csharpprojects\TestProject>
Take a minute to consider why the compiler was unable to run the first code sample.
The important part of the error message,
(3,14): error CS0029: Cannot implicitly convert type 'string' to 'int'
, tells
you the problem is with the use of the string data type.
But why can't the C# Compiler just handle the error? After all, you can do the
opposite to concatenate a number to a string
and save it in a string variable.
Here, you change the data type of the result
variable from int
to string.
Update your code in the editor as follows:
int first = 2;
string second = "4";
string result = first + second;
Console.WriteLine(result);
Save your code file, and then run your code.
You should observe the following output:
24
The output is mathematically incorrect but completes by combining the values as the characters "2" and "4".
Examine, once again, the first code example where the result
variable is of
type int
. The code with the error message.
int first = 2;
string second = "4";
int result = first + second;
Console.WriteLine(result);
Why can't the C# compiler figure out that you want to treat the variable second
containing 4
as a number, not a string
?
Compilers make safe conversions
The C# compiler sees a potential problem in the making. The variable second
is
of type string
, so it might be set to a different value like "hello"
. If the
C# compiler attempted to convert "hello" to a number that would cause an
exception at runtime. To avoid this possibility, the C# compiler doesn't
implicitly perform the conversion from string
to int
for you.
From the C# compiler's perspective, the safer operation would be to convert
int
into a string
and perform concatenation instead.
If you intend to perform addition using a string, the C# compiler requires you to take more explicit control of the process of data conversion. In other words, it forces you to be more involved so that you can put the proper precautions in place to handle the possibility that the conversion could throw an exception.
If you need to change a value from the original data type to a new data type and the change could produce an exception at run time, you must perform a data conversion.
To perform data conversion, you can use one of several techniques:
- Use a helper method on the data type
- Use a helper method on the variable
- Use the Convert class' methods
You look at a few examples of these techniques for data conversion later in this unit.
Question
Is it possible that attempting to change the value's data type would result in a loss of information?
Delete or use the line comment operator //
to comment out the code from the
previous exercise step, and add the following code:
int myInt = 3;
Console.WriteLine($"int: {myInt}");
decimal myDecimal = myInt;
Console.WriteLine($"decimal: {myDecimal}");
Save your code file, and then run your code.
You should see the following output:
int: 3
decimal: 3
The key to this example is this line of code:
decimal myDecimal = myInt;
Since any int
value can easily fit inside of a decimal
, the compiler performs
the conversion.
The term widening conversion means that you're attempting to convert a value
from a data type that could hold less information to a data type that
can hold more information. In this case, a value stored in a variable of type
int
converted to a variable of type decimal
, doesn't lose information.
When you know you're performing a widening conversion, you can rely on implicit conversion. The compiler handles implicit conversions.
Perform a cast
Delete or use the line comment operator //
to comment out the code from the
previous exercise step, and add the following code:
decimal myDecimal = 3.14m;
Console.WriteLine($"decimal: {myDecimal}");
int myInt = (int)myDecimal;
Console.WriteLine($"int: {myInt}");
To perform a cast, you use the casting operator ()
to surround a data type,
then place it next to the variable you want to convert (example:
(int)myDecimal
). You perform an explicit conversion to the defined cast data
type (int
).
Save your file, and then run your code.
You should see the following output:
decimal: 3.14
int: 3
The key to this example is this line of code:
int myInt = (int)myDecimal;
The variable myDecimal
holds a value that has precision after the decimal poin
t. By adding the casting instruction (int)
, you're telling the C# compiler that
you understand it's possible you'll lose that precision, and in this situation,
it's fine. You're telling the compiler that you're performing an intentional
conversion, an explicit conversion.
Determine if your conversion is a "widening conversion" or a "narrowing conversion"
The term narrowing conversion means that you're attempting to convert a value
from a data type that can hold more information to a data type that can hold
less information. In this case, you may lose information such as precision
(that is, the number of values after the decimal point). An example is
converting value stored in a variable of type decimal
into a variable of type
int
. If you print the two values, you would possibly notice the loss of
information.
When you know you're performing a narrowing conversion, you need to perform a cast. Casting is an instruction to the C# compiler that you know precision may be lost, but you're willing to accept it.
If you're unsure whether you lose data in the conversion, write code to perform a conversion in two different ways and observe the changes. Developers frequently write small tests to better understand the behaviors, as illustrated with the next sample.
Delete or use the line comment operator //
to comment out the code from the
previous exercise step, and add the following code:
decimal myDecimal = 1.23456789m;
float myFloat = (float)myDecimal;
Console.WriteLine($"Decimal: {myDecimal}");
Console.WriteLine($"Float : {myFloat}");
Save your file, and then run your code.
You should see output similar to:
Decimal: 1.23456789
Float : 1.2345679
You can observe from the output that casting a decimal
into a float
is a
narrowing conversion because you're losing precision.
Performing Data Conversions
Earlier, it was stated that a value change from one data type into another could cause a runtime exception, and you should perform data conversion. For data conversions, there are three techniques you can use:
- Use a helper method on the variable
- Use a helper method on the data type
- Use the
Convert
class' methods
Use ToString()
to convert a number to a string
Every data type variable has a ToString()
method. What the ToString()
method
does depends on how it's implemented on a given type. However, on most
primitives, it performs a widening conversion. While this isn't strictly
necessary (since you can rely on implicit conversion in most cases) it can
communicate to other developers that you understand what you're doing and it's
intentional.
Here's a quick example of using the ToString()
method to explicitly convert
int
values into strings.
Delete or use the line comment operator //
to comment out the code from the
previous exercise step, and add the following code:
int first = 5;
int second = 7;
string message = first.ToString() + second.ToString();
Console.WriteLine(message);
Save your file, and then run the code, the output should display a concatenation of the two values:
57
Convert a string
to an int
using the Parse()
helper method
Most of the numeric data types have a Parse()
method, which converts a
string
into the given data type. In this case, you use the Parse()
method
to convert two strings into int values, then add them together.
Delete or use the line comment operator //
to comment out the code from the
previous exercise step, and add the following code:
string first = "5";
string second = "7";
int sum = int.Parse(first) + int.Parse(second);
Console.WriteLine(sum);
Save your file, and then run the code, the output should display a sum of the two values:
12
Take a minute to try to spot the potential problem with the previous code
example. What if either of the variables first
or second
are set to values
that can't be converted to an int
? An exception is thrown at runtime. The C#
compiler and runtime expects you to plan ahead and prevent "illegal"
conversions. You can mitigate the runtime exception in several ways.
The easiest way to mitigate this situation is by using TryParse()
, which is a
better version of the Parse()
method.
Convert a string
to a int
using the Convert
class
The Convert
class has many helper methods to convert a value from one type
into another. In the following code example, you convert a couple of strings
into values of type int
.
Note
The code samples in this exercise are designed based on en-US culture setting s, and use a period (.
) as the decimal separator. Building and running the code with a culture setting that uses a different decimal separators (such as a comma,
) may give unexpected results or errors. To fix this issue, replace the period decimal separators in the code samples with your local decimal separator (such as,
). Alternatively, to run a program using the en-US culture setting, add the following code to the top of your program:using System.Globalization;
and after any otherusing
statements addCultureInfo.CurrentCulture = new CultureInfo("en-US");
.
Delete or use the line comment operator //
to comment out the code from the
previous exercise step, and add the following code:
string value1 = "5";
string value2 = "7";
int result = Convert.ToInt32(value1) * Convert.ToInt32(value2);
Console.WriteLine(result);
Save your file, and then run your code.
You should see the following output:
35
Note
Why is the method nameToInt32()
? Why notToInt()
?
System.Int32
is the name of the underlying data type in the .NET Class Library that the C# programming language maps to the keywordint
. Because theConvert
class is also part of the .NET Class Library, it is called by its full name, not its C# name. By defining data types as part of the .NET Class Library, multiple .NET languages like Visual Basic, F#, IronPython, and others can share the same data types and the same classes in the .NET Class Library.
The ToInt32()
method has 19 overloaded versions allowing it to accept
virtually every data type.
you used the Convert.ToInt32()
method with a string here, but you should
probably use TryParse()
when possible.
So, when should you use the Convert
class? The Convert
class is best for
converting fractional numbers into whole numbers (int
) because it rounds up
the way you would expect.
Compare casting and converting a decimal
into an int
The following example demonstrates what happens when you attempt to cast a
decimal
into an int
(a narrowing conversion) versus using the
Convert.ToInt32()
method to convert the same decimal
into an int
.
Delete or use the line comment operator //
to comment out the code from the
previous exercise step, and add the following code:
int value = (int)1.5m; // casting truncates
Console.WriteLine(value);
int value2 = Convert.ToInt32(1.5m); // converting rounds up
Console.WriteLine(value2);
Save your file, and then run your code.
You should see the following output:
1
2
Casting truncates and converting rounds
When you're casting int value = (int)1.5m;
, the value of the float is truncated
so the result is 1
, meaning the value after the decimal is ignored completely.
You could change the literal float to 1.999m
and the result of casting would
be the same.
When you're converting using Convert.ToInt32()
, the literal float value is
properly rounded up to 2
. If you changed the literal value to 1.499m
, it
would be rounded down to 1
.
Recap
You covered several important concepts of data conversion and casting:
- Prevent a runtime error while performing a data conversion
- Perform an explicit cast to tell the compiler you understand the risk of losing data
- Rely on the compiler to perform an implicit cast when performing an expanding conversion
- Use the
()
cast operator and the data type to perform a cast (for example,(int)myDecimal
) - Use the
Convert
class when you want to perform a narrowing conversion, but want to perform rounding, not a truncation of information