DEV Community

mohamed Tayel
mohamed Tayel

Posted on • Edited on

Mastering C# Fundamentals: Exploring Data Types in C#

Meta Description: Learn the fundamentals of data types in C#, including type safety, memory allocation, and predefined types like int, bool, and string. Explore how C# ensures strong typing and how expressions evaluate within the language to build safer, more efficient code.

Exploring Data Types in C

In C#, data types are foundational to how the language functions. Understanding data types helps us manage memory effectively, handle data, and ensure that our programs are safe and efficient. In this article, we’ll explore the core concepts of data types, starting with the basics.

Strongly Typed Language

C# is a strongly typed language, meaning that every variable must have a defined type when it is declared. The type of a variable specifies what kind of data it can store, such as integers, strings, or even custom types. Once a variable's type is defined, it cannot change throughout its lifetime. This strictness ensures consistency and type safety, which are checked during compile time.

When declaring a variable, the compiler ensures that the type assigned to it remains the same throughout its usage. For instance, declaring an int variable means that this variable will only store integers, and any attempt to assign it another type, such as a bool, would result in a compile-time error.


Using Data Types in C

There are three main aspects to understand about data types in C#:

  1. Size and Location in Memory:
    Each data type has a specific size that determines how much memory is allocated to store that variable. For example, an int takes up 4 bytes, and a bool only uses 1 bit for true or false values. The location of the data in memory is also important: value types are stored on the stack, while reference types are stored on the heap. This distinction is critical for understanding performance and memory usage in C# applications.

  2. Data Range:
    Every data type has a predefined range of values it can store. For example, the byte type can store values between 0 and 255, while an int can store much larger values, ranging from -2,147,483,648 to 2,147,483,647. Understanding these ranges helps avoid overflow and ensures the appropriate data type is selected for the task at hand.

  3. Supported Operations:
    Depending on the data type, certain operations can be performed. For instance, integers (int) support arithmetic operations like addition, subtraction, multiplication, and division. However, trying to apply these operations to non-numeric types, such as Booleans (bool), will result in errors. C# ensures that operations are compatible with the types on which they are performed.


More Predefined Data Types

In addition to basic types, C# provides several predefined data types that offer flexibility when handling different kinds of data. These include:

  • byte (sbyte): A byte is an 8-bit unsigned integer that holds values between 0 and 255. The sbyte is its signed counterpart, which allows for negative values ranging from -128 to 127.

  • short (ushort): The short type is a 16-bit signed integer that stores values from -32,768 to 32,767. Its unsigned version, ushort, holds only positive values, ranging from 0 to 65,535.

  • object: The object type is the base type from which all other types derive. Any type can be stored in an object variable, but you will often need to cast it back to its original type before using it. This flexibility comes at the cost of performance, especially when casting is frequent.

  • string: The string type is used to store sequences of characters and is widely used for text manipulation. Strings are immutable, meaning that once they are created, they cannot be changed. Any modifications result in the creation of a new string in memory.


Creating an Integer Value

Let us now create a simple integer value using C# code:

var yearlySalary = 1500;
int weeks = 52, annualBonus = 2000;
Enter fullscreen mode Exit fullscreen mode

In this example, we declare a variable yearlySalary and assign it the value of 1500. The keyword int is used for integer variables, and in one line, we also declare two more integer variables, weeks and annualBonus, and assign them values of 52 and 2000, respectively. Declaring multiple variables in one statement is a common and efficient way of handling related values of the same type.


Exploring Primitive Types in Visual Studio

Let us return to Visual Studio and explore more about working with primitive types. When creating variables, we always need to start with the type because it defines the values that can be stored in the variable and the range of values it can hold.

For example, if we want to store a value of type integer, we use the int keyword. Visual Studio highlights it in blue because it’s a keyword, making it easier to identify in the editor. When naming variables, we follow the camelCase convention—starting with a lowercase letter and capitalizing each subsequent word. This is important for clarity and readability.

int yearlySalary = 1500;
Enter fullscreen mode Exit fullscreen mode

Here, yearlySalary is our integer variable. The type int defines that it can only hold integer values. Now, let’s declare multiple variables in one line:

int weeks = 52, annualBonus = 2000;
Enter fullscreen mode Exit fullscreen mode

This single line declares two integer variables, weeks and annualBonus, and assigns them values. We can declare multiple variables this way as long as they are of the same type.


Working with Other Types

C# supports various other types beyond integers. For example, we can declare a Boolean variable (bool), which holds true or false values. We can also use double for floating-point numbers, which store decimal values.

bool isAvailable = true;
double reviewScore = 88.75;
Enter fullscreen mode Exit fullscreen mode

Here, we’ve declared a Boolean isAvailable and set it to true, and a double reviewScore with a value of 88.75.


Type Safety in C

C# also provides strict type safety. This means that the value assigned to a variable must match its declared type. If you attempt to assign a value outside the allowed range, the compiler will flag an error. For example, if you declare a byte, which can store values between 0 and 255, and then try to assign a larger value, the compiler will not allow it.

//byte numberOfItems = 300;  // This will cause an error because 300 is outside the valid range for byte.
Enter fullscreen mode Exit fullscreen mode

This is a demonstration of how the compiler helps prevent runtime errors by flagging issues at compile time.


Changing Values in a Variable

While C# enforces type safety, you can still update the value of a variable as long as the new value is of the same type. For example, if you have a variable for tracking hours worked, you can change the value during the program’s execution:

int hoursWorked;
hoursWorked = 110;
hoursWorked = 135;
Enter fullscreen mode Exit fullscreen mode

Here, we first declare hoursWorked, assign it a value of 110, and later update it to 135. However, you cannot change the type of the variable. For instance, you cannot assign a Boolean value to an integer variable:

// yearlySalary = true;  // This will cause an error because `true` is not an integer value.
Enter fullscreen mode Exit fullscreen mode

Once a variable’s type is declared, it must remain consistent throughout the code.


Working with Constants

So far, the variables we have worked with can be changed during the program’s execution. This flexibility is useful, but there are situations where you may want to work with a value that should never change. In such cases, C# provides the const keyword to declare a constant. A constant ensures that a value remains unchanged throughout the execution of the program.

For instance, if we are working with an interest rate, we may want to ensure that the interest rate remains fixed and cannot be modified by accident. Here’s how you can use the const keyword:

const double interestRate = 0.07;
Enter fullscreen mode Exit fullscreen mode

In this example, interestRate is declared as a constant using the const keyword before the type declaration. This means that interestRate can never be changed during the program’s execution. If you attempt to assign a new value to it later, the compiler will flag an error:

// interestRate = 0.08;  // This will cause an error because `interestRate` is a constant and cannot be modified.
Enter fullscreen mode Exit fullscreen mode

The compiler will prevent any changes to constants, providing additional safety when working with fixed values that should not change.


Working with Strings

So far, we have worked with numeric and Boolean values. Apart from using them in combination with the console, we haven't worked with text much. C# has full support for working with text in the form of strings. Strings are a special case in C#. Not only can you do a lot with them, but they also behave differently from other types. For this reason, an entire module is often dedicated to them. However, let’s get a brief introduction to strings here.

A string in C# consists of a series of characters, or chars. Think of it as a list of characters that represent a piece of text. The text can be short (like a single word or even just a space) or long (like an entire book). When creating a string in C#, the text is surrounded by double quotes ("),

unlike a char which uses single quotes ('). Here’s an example:

string greeting = "Hello, world!";
Enter fullscreen mode Exit fullscreen mode

In this case, greeting is a string containing the text "Hello, world!". Notice how the text is enclosed in double quotes, indicating the start and end of the string.

A string can also be empty. We can create an empty string by using double quotes with nothing between them:

string emptyString = "";
Enter fullscreen mode Exit fullscreen mode

Or, we can use string.Empty, which is a predefined constant that represents an empty string:

string emptyString = string.Empty;
Enter fullscreen mode Exit fullscreen mode

This is a shorthand for creating empty strings in C#. There are many helper methods built into the string type to make working with text easier, which we will explore in more detail later.
Here's a table that outlines the size, memory location, data range, and supported operations for common C# data types:

Data Type Size Memory Location Data Range Supported Operations
byte 1 byte Stack 0 to 255 Arithmetic (+, -, *, /), Bitwise operations (&, `
{% raw %}sbyte 1 byte Stack -128 to 127 Arithmetic, Bitwise operations
short 2 bytes Stack -32,768 to 32,767 Arithmetic, Bitwise operations
ushort 2 bytes Stack 0 to 65,535 Arithmetic, Bitwise operations
int 4 bytes Stack -2,147,483,648 to 2,147,483,647 Arithmetic, Bitwise operations, Comparison (==, !=, <, >, etc.)
uint 4 bytes Stack 0 to 4,294,967,295 Arithmetic, Bitwise operations, Comparison
long 8 bytes Stack -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 Arithmetic, Bitwise operations, Comparison
ulong 8 bytes Stack 0 to 18,446,744,073,709,551,615 Arithmetic, Bitwise operations, Comparison
float 4 bytes Stack ~±1.5 x 10^−45 to ±3.4 x 10^38 Arithmetic, Comparison, Mathematical functions (e.g., Math.Abs, Math.Sqrt)
double 8 bytes Stack ~±5.0 × 10^−324 to ±1.7 × 10^308 Arithmetic, Comparison, Mathematical functions
decimal 16 bytes Stack ~±1.0 x 10^−28 to ±7.9 x 10^28 Arithmetic, Comparison (best for financial calculations)
char 2 bytes Stack Unicode 0 to 65,535 Comparison, Concatenation (when used in strings), Character-specific operations (e.g., char.IsDigit)
bool 1 bit Stack true or false Logical operations (&&, `
{% raw %}string Variable Heap N/A (depends on content) Concatenation (+, +=), String-specific operations (e.g., string.Contains, string.Substring)
object Variable Heap N/A (can store any type) Casting, Comparison (==, !=), Type-specific operations after casting

This table summarizes the characteristics of each data type, helping you understand their size, memory behavior, value ranges, and the kinds of operations they support.


Here are assignments at three levels (easy, medium, and difficult) for the article on data types in C#. Each level is designed to reinforce understanding of the concepts covered:

Easy Assignment

Task: Create and manipulate basic data types in C#.

  1. Create three variables: an integer (int), a floating-point number (double), and a Boolean (bool).
  2. Assign initial values to each variable.
  3. Change the value of the integer variable and print all three variables to the console.

Example:

int age = 25;
double salary = 55000.75;
bool isEmployed = true;

// Change the value of the integer
age = 30;

Console.WriteLine($"Age: {age}, Salary: {salary}, Employed: {isEmployed}");
Enter fullscreen mode Exit fullscreen mode

Medium Assignment

Task: Use constants and explore type safety in C#.

  1. Declare a constant PI and assign it the value 3.14159.
  2. Declare an integer variable to represent the radius of a circle and calculate the circle’s area using the formula Area = PI * radius * radius.
  3. Try to reassign a value to the constant PI and observe the compiler error.
  4. Print the calculated area to the console.

Example:

const double PI = 3.14159;
int radius = 5;
double area = PI * radius * radius;

Console.WriteLine($"Area of the circle: {area}");

// Uncommenting the following line will cause a compiler error
// PI = 3.14;
Enter fullscreen mode Exit fullscreen mode

Difficult Assignment

Task: Create variables using different data types and implement error handling for type mismatches.

  1. Create a program that declares variables of various data types, such as byte, short, int, long, double, string, and bool.
  2. Assign values that are within the allowed range for each data type.
  3. Attempt to assign a value that exceeds the range for one of the variables (e.g., assign 300 to a byte).
  4. Use a try-catch block to catch and handle the error gracefully.
  5. Print the variables to the console, displaying both valid and invalid assignments.

Example:

try
{
    byte age = 255; // Max value for byte
    age = 300; // This will cause an error

    short height = 150;
    int population = 7000000;
    long distance = 10000000000L;
    double gdp = 12345.67;
    string country = "USA";
    bool isSafe = true;

    Console.WriteLine($"Age: {age}, Height: {height}, Population: {population}, Distance: {distance}, GDP: {gdp}, Country: {country}, Safe: {isSafe}");
}
catch (OverflowException ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Understanding data types is crucial when working with C#. They not only dictate the kind of data a variable can store but also control how much memory it uses, where it's stored, and what operations can be performed on it. Whether you're working with integers, Booleans, floating-point numbers, constants, or strings, C# enforces strong type safety to ensure that your programs are robust and error-free.

Top comments (0)