Skip to main content

C# Data Types

Introduction

Data types are a fundamental concept in programming that define what kind of data a variable can hold. In C#, as a strongly-typed language, every variable must have a specific data type that determines the size, range, and operations that can be performed on that variable. Understanding data types is crucial as it helps in efficient memory management, prevents errors, and makes your code more predictable.

In this tutorial, we'll explore the various data types available in C#, how to use them effectively, and best practices for working with them in real-world applications.

Built-in Data Types in C#

C# provides a rich set of built-in data types that can be categorized into:

  1. Value Types
  2. Reference Types
  3. Pointer Types (used mainly in unsafe code)

Let's dive into each category:

Value Types

Value types directly contain their data and are stored on the stack. When you assign a value type to another variable, a copy of the value is created.

Numeric Types

C# offers several numeric data types to handle different ranges of numbers:

Integer Types
csharp
// Integer types
byte myByte = 255; // 0 to 255 (unsigned 8-bit)
sbyte mySByte = -128; // -128 to 127 (signed 8-bit)
short myShort = -32768; // -32,768 to 32,767 (16-bit)
ushort myUShort = 65535; // 0 to 65,535 (unsigned 16-bit)
int myInt = 2147483647; // -2,147,483,648 to 2,147,483,647 (32-bit)
uint myUInt = 4294967295; // 0 to 4,294,967,295 (unsigned 32-bit)
long myLong = 9223372036854775807; // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 (64-bit)
ulong myULong = 18446744073709551615; // 0 to 18,446,744,073,709,551,615 (unsigned 64-bit)

// Output each value
Console.WriteLine($"byte value: {myByte}");
Console.WriteLine($"sbyte value: {mySByte}");
Console.WriteLine($"short value: {myShort}");
Console.WriteLine($"ushort value: {myUShort}");
Console.WriteLine($"int value: {myInt}");
Console.WriteLine($"uint value: {myUInt}");
Console.WriteLine($"long value: {myLong}");
Console.WriteLine($"ulong value: {myULong}");

Output:

byte value: 255
sbyte value: -128
short value: -32768
ushort value: 65535
int value: 2147483647
uint value: 4294967295
long value: 9223372036854775807
ulong value: 18446744073709551615
Floating-Point Types

Floating-point types are used to represent real numbers:

csharp
float myFloat = 3.14F;       // 7-digit precision (32-bit) - note the 'F' suffix
double myDouble = 3.14159265359; // 15-16 digit precision (64-bit)
decimal myDecimal = 3.14159265359m; // 28-29 significant digits (128-bit) - note the 'm' suffix

Console.WriteLine($"float value: {myFloat}");
Console.WriteLine($"double value: {myDouble}");
Console.WriteLine($"decimal value: {myDecimal}");

Output:

float value: 3.14
double value: 3.14159265359
decimal value: 3.14159265359
Money Matters

When working with financial calculations, always use the decimal type instead of float or double to avoid rounding errors that can occur in binary floating-point representations.

Boolean Type

The bool type can hold one of two values: true or false:

csharp
bool isActive = true;
bool isComplete = false;

Console.WriteLine($"Is active: {isActive}");
Console.WriteLine($"Is complete: {isComplete}");

Output:

Is active: True
Is complete: False

Character Type

The char type represents a Unicode UTF-16 character:

csharp
char myChar = 'A';
char unicodeChar = '\u0041'; // Unicode for 'A'

Console.WriteLine($"Character: {myChar}");
Console.WriteLine($"Unicode character: {unicodeChar}");

Output:

Character: A
Unicode character: A

Struct Types

Structs are value types that can contain multiple fields and methods:

csharp
struct Point
{
public int X;
public int Y;

public Point(int x, int y)
{
X = x;
Y = y;
}

public override string ToString()
{
return $"({X}, {Y})";
}
}

// Using the struct
Point myPoint = new Point(10, 20);
Console.WriteLine($"Point coordinates: {myPoint}");

Output:

Point coordinates: (10, 20)

Enum Type

Enums define a set of named constants:

csharp
enum DaysOfWeek
{
Sunday = 0,
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6
}

DaysOfWeek today = DaysOfWeek.Wednesday;
Console.WriteLine($"Today is {today}");
Console.WriteLine($"Today's numeric value is {(int)today}");

Output:

Today is Wednesday
Today's numeric value is 3

Reference Types

Reference types store a reference to the memory location where the actual data is kept, typically on the managed heap.

String Type

The string type represents a sequence of characters:

csharp
string greeting = "Hello, World!";
string emptyString = string.Empty; // Same as ""
string nullString = null;
string interpolatedString = $"The greeting is: {greeting}";

Console.WriteLine(greeting);
Console.WriteLine($"Length of greeting: {greeting.Length}");
Console.WriteLine(interpolatedString);

Output:

Hello, World!
Length of greeting: 13
The greeting is: Hello, World!

Object Type

object is the base class for all other types in C#:

csharp
object myObject = 42;          // Boxing an int
object stringObject = "text"; // Reference to a string
object dateObject = DateTime.Now;

Console.WriteLine($"Integer object: {myObject}");
Console.WriteLine($"String object: {stringObject}");
Console.WriteLine($"Date object: {dateObject}");

Output:

Integer object: 42
String object: text
Date object: 5/20/2023 2:15:30 PM (varies based on current date/time)

Array Type

Arrays can hold multiple values of the same type:

csharp
// Declaration and initialization of arrays
int[] numbers = { 1, 2, 3, 4, 5 };
string[] fruits = new string[3] { "Apple", "Banana", "Cherry" };

// Accessing array elements
Console.WriteLine($"First number: {numbers[0]}");
Console.WriteLine($"Second fruit: {fruits[1]}");

// Iterating through an array
Console.WriteLine("All numbers:");
foreach (int num in numbers)
{
Console.Write($"{num} ");
}

Output:

First number: 1
Second fruit: Banana
All numbers:
1 2 3 4 5

Class Type

Classes are the primary reference types in C#:

csharp
class Person
{
public string Name { get; set; }
public int Age { get; set; }

public Person(string name, int age)
{
Name = name;
Age = age;
}

public override string ToString()
{
return $"{Name}, {Age} years old";
}
}

// Creating and using a class instance
Person person = new Person("John", 30);
Console.WriteLine(person);

Output:

John, 30 years old

Type Conversion

C# provides several ways to convert between data types:

Implicit Conversion

Occurs automatically when there's no risk of data loss:

csharp
int myInt = 100;
long myLong = myInt; // Implicit conversion from int to long
float myFloat = myInt; // Implicit conversion from int to float

Console.WriteLine($"Original int: {myInt}");
Console.WriteLine($"Converted to long: {myLong}");
Console.WriteLine($"Converted to float: {myFloat}");

Output:

Original int: 100
Converted to long: 100
Converted to float: 100

Explicit Conversion (Casting)

Required when there's potential for data loss:

csharp
double myDouble = 9.78;
int myInt = (int)myDouble; // Explicit conversion, fractional part is truncated

Console.WriteLine($"Original double: {myDouble}");
Console.WriteLine($"Converted to int: {myInt}");

Output:

Original double: 9.78
Converted to int: 9

Using Conversion Methods

C# provides built-in methods for type conversion:

csharp
string numberString = "123";
int parsedInt = int.Parse(numberString);
int convertedInt = Convert.ToInt32(numberString);

double potentialDouble = 123.45;
string doubleString = potentialDouble.ToString();

Console.WriteLine($"Original string: {numberString}");
Console.WriteLine($"Parsed to int: {parsedInt}");
Console.WriteLine($"Converted to int: {convertedInt}");
Console.WriteLine($"Double to string: {doubleString}");

Output:

Original string: 123
Parsed to int: 123
Converted to int: 123
Double to string: 123.45

TryParse Methods

For safer conversions that handle potential errors:

csharp
string validNumber = "123";
string invalidNumber = "abc";

if (int.TryParse(validNumber, out int result1))
{
Console.WriteLine($"Successfully parsed: {result1}");
}
else
{
Console.WriteLine("Parsing failed");
}

if (int.TryParse(invalidNumber, out int result2))
{
Console.WriteLine($"Successfully parsed: {result2}");
}
else
{
Console.WriteLine("Parsing failed");
}

Output:

Successfully parsed: 123
Parsing failed

Nullable Types

C# allows value types to be nullable using the ? modifier:

csharp
// Nullable types
int? nullableInt = null;
bool? nullableBool = null;
double? nullableDouble = 3.14;

// Using nullable types
Console.WriteLine($"Nullable int has value: {nullableInt.HasValue}");
Console.WriteLine($"Nullable double value: {nullableDouble.GetValueOrDefault()}");

// Null-coalescing operator
int definiteInt = nullableInt ?? -1;
Console.WriteLine($"Definite int value: {definiteInt}");

Output:

Nullable int has value: False
Nullable double value: 3.14
Definite int value: -1

Var Keyword - Implicit Typing

The var keyword allows C# to infer the type during compilation:

csharp
var message = "Hello"; // Inferred as string
var number = 42; // Inferred as int
var date = DateTime.Now; // Inferred as DateTime

Console.WriteLine($"message is of type: {message.GetType()}");
Console.WriteLine($"number is of type: {number.GetType()}");
Console.WriteLine($"date is of type: {date.GetType()}");

Output:

message is of type: System.String
number is of type: System.Int32
date is of type: System.DateTime
Important Note

The var keyword doesn't make C# dynamically typed. The type is still inferred at compile-time and can't change during runtime.

Real-World Examples

Building a Simple Calculator

csharp
double num1 = 10.5;
double num2 = 5.25;

// Basic operations
double sum = num1 + num2;
double difference = num1 - num2;
double product = num1 * num2;
double quotient = num1 / num2;

Console.WriteLine("Simple Calculator");
Console.WriteLine($"{num1} + {num2} = {sum}");
Console.WriteLine($"{num1} - {num2} = {difference}");
Console.WriteLine($"{num1} * {num2} = {product}");
Console.WriteLine($"{num1} / {num2} = {quotient}");

Output:

Simple Calculator
10.5 + 5.25 = 15.75
10.5 - 5.25 = 5.25
10.5 * 5.25 = 55.125
10.5 / 5.25 = 2

Product Inventory System

csharp
class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }

public Product(string name, decimal price, int quantity)
{
Name = name;
Price = price;
Quantity = quantity;
}

public decimal CalculateValue()
{
return Price * Quantity;
}
}

// Creating a product inventory
Product[] inventory = new Product[]
{
new Product("Laptop", 1299.99m, 5),
new Product("Mouse", 25.50m, 20),
new Product("Keyboard", 45.99m, 10)
};

// Calculating total inventory value
decimal totalValue = 0;
foreach (Product product in inventory)
{
decimal productValue = product.CalculateValue();
totalValue += productValue;
Console.WriteLine($"{product.Name}: {product.Quantity} units at ${product.Price} = ${productValue}");
}

Console.WriteLine($"\nTotal inventory value: ${totalValue}");

Output:

Laptop: 5 units at $1299.99 = $6499.95
Mouse: 20 units at $25.50 = $510.00
Keyboard: 10 units at $45.99 = $459.90

Total inventory value: $7469.85

Temperature Converter

csharp
// Function to convert Celsius to Fahrenheit
double CelsiusToFahrenheit(double celsius)
{
return celsius * 9 / 5 + 32;
}

// Function to convert Fahrenheit to Celsius
double FahrenheitToCelsius(double fahrenheit)
{
return (fahrenheit - 32) * 5 / 9;
}

// Test the converter
double[] celsiusTemperatures = { 0, 25, 100 };

Console.WriteLine("Temperature Converter");
Console.WriteLine("---------------------");
foreach (double c in celsiusTemperatures)
{
double f = CelsiusToFahrenheit(c);
Console.WriteLine($"{c}°C = {f}°F");
}

Console.WriteLine("\nReverse conversion:");
double[] fahrenheitTemperatures = { 32, 77, 212 };
foreach (double f in fahrenheitTemperatures)
{
double c = FahrenheitToCelsius(f);
Console.WriteLine($"{f}°F = {c}°C");
}

Output:

Temperature Converter
---------------------
0°C = 32°F
25°C = 77°F
100°C = 212°F

Reverse conversion:
32°F = 0°C
77°F = 25°C
212°F = 100°C

Summary

In this tutorial, we've covered the essential data types in C#:

  • Value Types: Including numeric types (integer and floating-point), boolean, character, struct, and enum types.
  • Reference Types: Including strings, objects, arrays, and custom classes.
  • Type Conversion: Both implicit and explicit conversions, as well as parsing methods.
  • Nullable Types: How to declare and work with nullable value types.
  • Var Keyword: Using implicit typing to make code more concise.

Understanding data types is fundamental to writing effective C# programs. Choosing the right data type for your variables ensures optimal memory usage, prevents potential errors, and makes your code more maintainable.

Additional Resources

Exercises

  1. Create a program that converts user input (as string) to different numeric data types and handles potential conversion errors.
  2. Implement a simple banking system that uses appropriate data types for account balances, customer names, and transaction dates.
  3. Create a temperature class that stores temperature in Celsius but provides properties to get and set the value in Fahrenheit and Kelvin.
  4. Design a program that demonstrates the differences between value types and reference types by showing how they behave when passed to methods.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)