In C#, a data type defines the type of value a variable can hold. Understanding the different data types in C# is essential because it allows you to choose the most appropriate one for your data, ensuring your programs are efficient, easy to maintain, and free of errors.
C# has two main categories of data types: value types and reference types. Each category has different characteristics and is used for different purposes. This guide will explore all the built-in data types in C#, their sizes, and when to use each one.
1. Value Types vs. Reference Types
Value Types: Store the data directly in memory. When you assign one variable to another, the value is copied. Examples include int, float, bool, etc.
Reference Types: Store references (addresses) to data in memory. When you assign one reference type variable to another, both variables point to the same data. Examples include string, array, object, etc.
2. Value Types
Value types hold data directly and are stored in the stack. When a value type is assigned to another, a copy of the value is made. There are several categories of value types in C#:
2.1. Numeric Types
These types are used to store numeric values (both integers and floating-point numbers).
• int: Stores 32-bit signed integers.
Range: -2,147,483,648 to 2,147,483,647
Example: int age = 25;
• long: Stores 64-bit signed integers.
Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
Example: long distance = 1234567890123L;
• short: Stores 16-bit signed integers.
Range: -32,768 to 32,767
Example: short temperature = -10;
• byte: Stores 8-bit unsigned integers (0 to 255).
Range: 0 to 255
Example: byte level = 100;
• float: Stores single-precision 32-bit floating-point numbers (decimals).
Range: ±1.5 × 10^−45 to ±3.4 × 10^38
Example: float price = 99.99f;
• double: Stores double-precision 64-bit floating-point numbers (higher precision than float).
Range: ±5.0 × 10^−324 to ±1.7 × 10^308
Example: double distance = 123.4567890123;
• decimal: Stores 128-bit precise decimal values. Useful for financial calculations due to its high precision.
Range: ±1.0 × 10^−28 to ±7.9 × 10^28
Example: decimal salary = 1999.99m;
2.2. Boolean Type
• bool: Represents a boolean value, either true or false.
Example: bool isActive = true;
2.3. Character Type
• char: Stores a single 16-bit Unicode character.
Range: 0 to 65,535
Example: char grade = 'A';
2.4. Structs and Enumerations
In addition to the primitive types, value types can also be structs and enums:
• struct: A user-defined type that can store multiple related values of different types.
Example: DateTime, Point.
• enum: A special "class" that defines a group of constants under a single name. Example:
enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }
3. Reference Types
Reference types store the address (or reference) to the data. The data itself is stored on the heap, and variables hold references to this memory. When a reference type is assigned to another, both variables point to the same data.
3.1. String
• string: Represents a sequence of characters. It’s technically a reference type, but it behaves like a value type in C# because strings are immutable (cannot be changed).
string name = "Alice";
3.2. Object
• object: The base type for all types in C#. Every other type in C# (whether value or reference) inherits from object. It can store any type of data, but requires casting when retrieving the original type.
object obj = "Hello World";
3.3. Arrays
• array: A collection of elements of the same type. Arrays are reference types in C#, even though they store multiple items.
int[] numbers = { 1, 2, 3, 4, 5 };
3.4. Class
• class: A blueprint for creating objects. Classes can contain fields, properties, methods, and events. A class type is always a reference type.
Example:
class Person {
public string Name;
public int Age;
}
3.5. Delegates and Events
• delegate: A reference type that defines a method signature. It can be used to pass methods as arguments to other methods.
• event: A way for classes to send notifications to other classes.
4. Nullable Types
In C#, by default, value types cannot be null. However, you can make them nullable using the ? syntax.
int? age = null;
This is useful when you need to represent situations where a variable could be undefined or missing.
5. Type Conversion
C# supports implicit and explicit type conversions:
Implicit Conversion
An implicit conversion occurs when there is no risk of data loss.
Example:
int number = 10;
double result = number; // Implicit conversion from int to double
Explicit Conversion (Casting)
An explicit conversion (also known as casting) is required when you need to convert one type to another, and there is a risk of data loss.
Example:
double pi = 3.14;
int wholePi = (int)pi; // Explicit cast from double to int (loss of data)
Convert Class
The Convert class allows for safe conversions between types:
string number = "123";
int result = Convert.ToInt32(number); // Converts string to int
6. Special Data Types
6.1. Dynamic Type
• dynamic: A special type that bypasses compile-time type checking. The actual type is resolved at runtime.
dynamic obj = 5;
obj = "Hello";
6.2. Var Keyword
• var: A special keyword that allows the compiler to infer the type of the variable at compile time. It is not a data type, but it helps simplify code by letting the compiler determine the type.
var name = "Alice"; // compiler infers 'string' type
7. Size and Memory Usage of Data Types
Each data type in C# uses a specific amount of memory. Here’s a summary of the size of common data types:
| Data Type | Size | Description |
|---|---|---|
| bool | 1 byte | Stores true/false values |
| byte | 1 byte | Stores unsigned 8-bit integers |
| char | 2 bytes | Stores a single Unicode character |
| short | 2 bytes | Stores signed 16-bit integers |
| int | 4 bytes | Stores signed 32-bit integers |
| long | 8 bytes | Stores signed 64-bit integers |
| float | 4 bytes | Stores 32-bit floating-point numbers |
| double | 8 bytes | Stores 64-bit floating-point numbers |
| decimal | 16 bytes | Stores high-precision decimal numbers |
| string | Depends on length | Variable-length string, uses 2 bytes per character |