Easy Learn C#

C# Data Types

Introduction to C# Data Types

C# is a strongly-typed language, which means every variable and constant has a specific data type that determines the size and layout of the variable's memory, the range of values that can be stored within that memory, and the set of operations that can be performed on the variable.

C# data types are divided into two main categories:

  • Value Types - Directly contain their data and are stored on the stack
  • Reference Types - Store a reference to their data, which is stored on the heap

Value Types

Value types hold the actual data within their own memory allocation. When you assign one value type to another, a copy of the value is created.

Value Type Behavior:


int a = 10;
int b = a;    // Value is copied, b now has its own copy of 10
a = 20;       // Changing a does not affect b
Console.WriteLine(b);  // Outputs: 10
                            

Common Value Types:

Category Type Size Range Example
Integer Types sbyte 8 bits -128 to 127 sbyte temperature = -10;
byte 8 bits 0 to 255 byte colorValue = 255;
short 16 bits -32,768 to 32,767 short elevation = -1500;
int 32 bits -2.1 billion to 2.1 billion int population = 37500000;
long 64 bits -9.2 quintillion to 9.2 quintillion long nationalDebt = 21000000000000L;
Unsigned Integers ushort 16 bits 0 to 65,535 ushort portNumber = 8080;
uint 32 bits 0 to 4.2 billion uint viewCount = 3000000000U;
ulong 64 bits 0 to 18.4 quintillion ulong distance = 18446744073709551615UL;
Floating Point float 32 bits ±1.5 × 10−45 to ±3.4 × 1038, 7-digit precision float pi = 3.14159F;
double 64 bits ±5.0 × 10−324 to ±1.7 × 10308, 15-16 digit precision double atomRadius = 0.000000001;
Decimal decimal 128 bits ±1.0 × 10-28 to ±7.9 × 1028, 28-29 significant digits decimal accountBalance = 3456.78M;
Boolean bool 8 bits* true or false bool isActive = true;
Character char 16 bits U+0000 to U+FFFF (Unicode characters) char grade = 'A';

* While a boolean logically only needs 1 bit, it typically uses 8 bits (1 byte) of storage due to memory alignment requirements.

Struct Types

Structs are value types that can contain multiple variables (fields), methods, and other members. They are useful for representing lightweight objects.

Custom Struct Example:


// Defining a struct
struct Point
{
    public int X;
    public int Y;
    
    // Constructor
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
    
    // Method
    public double DistanceFromOrigin()
    {
        return Math.Sqrt(X * X + Y * Y);
    }
}

// Using the struct
Point p1 = new Point(3, 4);
Console.WriteLine($"Distance from origin: {p1.DistanceFromOrigin()}");  // Outputs: 5
                            

Enum Types

Enumerations (enums) are distinct value types consisting of a set of named constants. They are useful for representing a fixed set of options or states.

Enum Example:


// Defining an enum
enum DaysOfWeek
{
    Monday,     // 0 by default
    Tuesday,    // 1
    Wednesday,  // 2
    Thursday,   // 3
    Friday,     // 4
    Saturday,   // 5
    Sunday      // 6
}

// Using an enum
DaysOfWeek today = DaysOfWeek.Wednesday;
Console.WriteLine(today);         // Outputs: Wednesday
Console.WriteLine((int)today);    // Outputs: 2

// Enum with explicit values
enum HttpStatusCode
{
    OK = 200,
    NotFound = 404,
    InternalServerError = 500
}

HttpStatusCode status = HttpStatusCode.NotFound;
Console.WriteLine($"Status: {status}, Code: {(int)status}");  // Outputs: Status: NotFound, Code: 404
                            

Reference Types

Reference types store a reference (or pointer) to the actual data in memory. When you assign one reference type to another, both variables refer to the same data.

Reference Type Behavior:


string a = "Hello";
string b = a;       // Both a and b reference the same string
a = "World";        // a now references a new string
Console.WriteLine(b);  // Outputs: Hello (unchanged)

// For objects (classes), changing properties affects all references
Person person1 = new Person { Name = "Alice" };
Person person2 = person1;   // Both reference the same object
person1.Name = "Bob";       // Change affects both references
Console.WriteLine(person2.Name);  // Outputs: Bob
                            

Common Reference Types:

Type Description Example
string Text (sequence of characters) string name = "John Smith";
class User-defined type with members Person employee = new Person();
object Base class for all types object data = 42;
dynamic Type resolved at runtime dynamic value = "test";
interface Contract defining members IEnumerable<int> numbers;
delegate Reference to a method Action<string> log;
array Collection of items int[] numbers = {1, 2, 3};

String Type

The string type represents a sequence of Unicode characters. Strings in C# are immutable, meaning once a string is created, its value cannot be changed.

String Examples:


// String declaration and initialization
string firstName = "John";
string lastName = "Smith";
string emptyString = string.Empty;  // Preferred way to create an empty string

// String concatenation
string fullName = firstName + " " + lastName;  // "John Smith"

// String interpolation (C# 6.0+)
string greeting = $"Hello, {firstName}!";  // "Hello, John!"

// String methods
string message = "   Learn C# Programming   ";
string trimmed = message.Trim();                  // "Learn C# Programming"
string uppercase = message.ToUpper();             // "   LEARN C# PROGRAMMING   "
string replaced = message.Replace("C#", "C++");   // "   Learn C++ Programming   "
bool contains = message.Contains("C#");           // true
int length = message.Length;                      // 27
int index = message.IndexOf("C#");                // 9

// String comparison
bool isEqual = firstName == "John";               // true
bool startsWithJ = firstName.StartsWith("J");     // true
bool ignoreCase = firstName.Equals("john", StringComparison.OrdinalIgnoreCase);  // true

// Verbatim string literal (preserves whitespace and newlines)
string path = @"C:\Program Files\Microsoft\Windows";  // No need to escape backslashes

// String with multiple lines
string multiline = @"This is a
multi-line
string";

// String interpolation with verbatim strings (C# 8.0+)
string combinedPath = $@"C:\Users\{userName}\Documents";
                            

Default Values

When a variable is declared but not initialized, it is assigned a default value based on its data type:

Type Default Value
Numeric types (int, float, etc.) 0 (appropriate for the type)
bool false
char '\0' (null character)
Reference types (string, class types) null
Struct types Each field set to its default value
enum types 0 (the value of the first enumerator)

Default Value Example:


// Explicit default values
int number = default;           // 0
bool flag = default;            // false
string text = default;          // null
double price = default;         // 0.0

// Using default expression (C# 7.1+)
DateTime date = default;        // 01/01/0001 00:00:00
int[] array = default;          // null

// Using default operator
var defaultInt = default(int);    // 0
var defaultBool = default(bool);  // false
var defaultString = default(string);  // null
                            

Special Types

Nullable Value Types

Value types normally cannot be assigned null. However, by using the nullable type decorator (?), value types can be made nullable.


// Regular value type cannot be null
// int regularInt = null;  // Error!

// Nullable value type can be null
int? nullableInt = null;
double? nullableDouble = null;

// Checking for null before using
if (nullableInt.HasValue)
{
    Console.WriteLine(nullableInt.Value);  // Safe to access value
}

// Null coalescing operator to provide a default value
int result = nullableInt ?? 0;  // If nullableInt is null, use 0
                            

var Keyword

The var keyword enables type inference, allowing the compiler to determine the type from the initialization expression.


// Type inference with var
var count = 10;              // Inferred as int
var name = "Alice";          // Inferred as string
var items = new List(); // Inferred as List
var today = DateTime.Now;    // Inferred as DateTime

// Restrictions:
// var must be initialized
// var price;  // Error! Must be initialized

// Type is fixed at compile-time
var number = 5;  // Type is int
// number = "string";  // Error! Cannot assign string to int
                            

dynamic Type

The dynamic type bypasses compile-time type checking. The type checking happens at runtime:


// Dynamic typing
dynamic value = 10;
Console.WriteLine(value);  // 10

value = "Hello";           // Can change type at runtime
Console.WriteLine(value);  // Hello

value = new List { 1, 2, 3 };
Console.WriteLine(value.Count);  // 3

// No compile-time checking
// Only runtime checking for methods/properties
dynamic obj = new { Name = "Test" };
Console.WriteLine(obj.Name);       // Works
// Console.WriteLine(obj.Missing);  // Runtime error!
                            

Type Checking

C# provides several ways to check the type of a variable:

Type Checking Examples:


object obj = "This is a string";

// Using is operator
if (obj is string)
{
    Console.WriteLine("obj is a string");
}

// Using GetType() and typeof
if (obj.GetType() == typeof(string))
{
    Console.WriteLine("obj is of type string");
}

// Using is with pattern matching (C# 7.0+)
if (obj is string message)
{
    // message is now a string variable containing the value of obj
    Console.WriteLine($"Message: {message}");
}

// Using switch expression with pattern matching (C# 8.0+)
string result = obj switch
{
    string s => $"String of length {s.Length}",
    int i => $"Integer: {i}",
    _ => "Unknown type"
};
                            

Best Practices for Working with Types

  • Choose the right type for your data to ensure memory efficiency and prevent overflow/underflow.
  • Use decimal for money calculations to avoid floating-point precision issues.
  • Avoid excessive type casting as it can lead to potential data loss and reduces code readability.
  • Use var when the type is obvious from initialization, but avoid it when clarity is important.
  • Use dynamic sparingly, as it bypasses compile-time type checking and can lead to runtime errors.
  • Consider using nullable types for database interactions where null values may be present.
  • Prefer string interpolation ($"...") over string concatenation for readability.

Test Your Knowledge: Data Types

Question 1: Which of the following is NOT a value type in C#?

Question 2: What is the default value of a boolean variable that has not been initialized?

Question 3: Which data type would be best for storing the precise monetary value $1,234.56?