In C#, variables are used to store values or references to objects in memory.
They must have a specified type, either explicitly or inferred, and follow certain rules for naming and scope.
Understanding variables is foundational to working with data in C# programs, as it allows you to store, modify, and retrieve values.
Basic Variable Types in C#
- Primitive Types: Built-in types like int, double, bool, char, etc.
- Reference Types: Variables that store references to objects, such as classes, arrays, and strings.
- Nullable Types: Allow value types to be assigned null.
- var Keyword: Allows type inference, where the compiler determines the type.
1. Declaring and Initializing Variables
To declare a variable, you specify the type followed by the variable name. Optionally, you can initialize it with a value.
using System; class Program { static void Main() { int age = 25; // Declares and initializes an integer variable double price = 19.99; // Declares and initializes a double variable bool isAvailable = true; // Declares and initializes a boolean variable char initial = 'A'; // Declares and initializes a char variable string name = "Alice"; // Declares and initializes a string variable Console.WriteLine($"Name: {name}, Age: {age}, Initial: {initial}, Price: {price}, Available: {isAvailable}"); } }
Explanation:
- Each variable has a type (int, double, etc.), a name (age, price), and an optional initial value.
Output:
Name: Alice, Age: 25, Initial: A, Price: 19.99, Available: True
2. Using var for Implicit Typing
The var keyword allows the compiler to infer the variable type based on the assigned value.
using System; class Program { static void Main() { var age = 30; // Inferred as int var name = "Bob"; // Inferred as string var price = 15.75; // Inferred as double var isActive = false; // Inferred as bool Console.WriteLine($"Name: {name}, Age: {age}, Price: {price}, Active: {isActive}"); } }
Explanation:
- The type is automatically determined by the compiler based on the assigned value.
- Note: Once inferred, the type of a var variable cannot change.
Output:
Name: Bob, Age: 30, Price: 15.75, Active: False
3. Constants with const
Constants are variables with values that cannot change after initialization. Use const to declare them.
using System; class Program { static void Main() { const double Pi = 3.14159; const int MaxScore = 100; Console.WriteLine($"Pi: {Pi}, Max Score: {MaxScore}"); } }
Explanation:
- const variables must be assigned a value at the time of declaration, and their values cannot be changed.
- Constants are useful for values that remain the same throughout the program.
Output:
Pi: 3.14159, Max Score: 100
4. Nullable Variables
In C#, value types cannot be null by default. To allow them to be null, use Nullable<T> or the shorthand T?.
using System; class Program { static void Main() { int? age = null; // Nullable integer double? price = 29.99; Console.WriteLine($"Age: {age}, Price: {price}"); age = 42; // Assigning a value to a previously null variable Console.WriteLine($"Updated Age: {age}"); } }
Explanation:
- int? allows age to be null.
- Nullable types are helpful when a variable may or may not have a value.
Output:
Age: , Price: 29.99 Updated Age: 42
5. Reference Type Variables
Reference types store a reference to the actual data. string, arrays, and custom classes are common reference types.
using System; class Person { public string Name { get; set; } } class Program { static void Main() { string name = "Charlie"; // Reference type int[] numbers = { 1, 2, 3 }; // Array, also a reference type Person person = new Person { Name = "Alice" }; Console.WriteLine($"Person Name: {person.Name}"); } }
Explanation:
- string and int[] are reference types, as is Person, a custom class.
- Modifying the reference does not create a new copy of the data but rather changes the existing data.
Output:
Person Name: Alice
6. readonly Variables
The readonly keyword allows you to declare variables whose values can only be set once, either at declaration or within a constructor.
using System; class Program { public readonly int MaxAttempts; public Program(int maxAttempts) { MaxAttempts = maxAttempts; // Can be assigned in the constructor } static void Main() { Program program = new Program(3); Console.WriteLine($"Max Attempts: {program.MaxAttempts}"); } }
Explanation:
- readonly variables can only be assigned at the time of declaration or in the constructor.
- They are useful for values that are set once and remain constant for the object’s lifetime.
Output:
Max Attempts: 3
7. Local Variables and Scope
Variables declared within a block (e.g., { }) are local to that block and cannot be accessed outside it.
using System; class Program { static void Main() { int number = 10; if (number > 5) { int localValue = 100; Console.WriteLine($"Inside if block: {localValue}"); } // Console.WriteLine(localValue); // Error: localValue is out of scope } }
Explanation:
- localValue is declared inside the if block, making it local to that block and inaccessible outside.
- Variable scope helps manage memory and avoid conflicts.
Output:
Inside if block: 100
8. Static Variables
Static variables belong to the class, not an instance, and are shared among all instances.
using System; class Counter { public static int count = 0; public Counter() { count++; } } class Program { static void Main() { Counter c1 = new Counter(); Counter c2 = new Counter(); Counter c3 = new Counter(); Console.WriteLine($"Count: {Counter.count}"); } }
Explanation:
- Counter.count is static, so it is shared across all instances of Counter.
- Every time a Counter instance is created, count is incremented.
Output:
Count: 3
9. Dynamic Variables with dynamic
The dynamic type allows the compiler to defer type checking until runtime. It is useful for cases where the type is not known at compile time.
using System; class Program { static void Main() { dynamic value = "Hello"; Console.WriteLine($"Value: {value}, Type: {value.GetType()}"); value = 42; Console.WriteLine($"Value: {value}, Type: {value.GetType()}"); } }
Explanation:
- The dynamic type can change its type at runtime.
- While flexible, dynamic can lead to runtime errors if misused.
Output:
Value: Hello, Type: System.String Value: 42, Type: System.Int32
10. Constant Expressions with const and readonly
const and readonly have different use cases in C#. const is compile-time constant, while readonly can be assigned at runtime.
using System; class Program { public const double Pi = 3.14159; // Compile-time constant public readonly double GoldenRatio; // Runtime constant public Program() { GoldenRatio = 1.618; } static void Main() { Program program = new Program(); Console.WriteLine($"Pi: {Program.Pi}, Golden Ratio: {program.GoldenRatio}"); } }
Explanation:
- const can only be initialized at declaration and cannot be changed.
- readonly can be initialized either at declaration or in a constructor, allowing it to vary at runtime.
Output:
Pi: 3.14159, Golden Ratio: 1.618
Summary Table of Variable Types
Example | Description |
---|---|
Declaring and Initializing | Standard variable declarations with initial values |
Implicit Typing with var | Compiler infers type from assigned value |
Constants with const | Immutable values known at compile-time |
Nullable Variables | Value types that can be null |
Reference Type Variables | Variables that store references to objects |
Readonly Variables | Variables that can be assigned only once |
Local Variables and Scope | Variables that exist within a limited block scope |
Static Variables | Class-level variables shared across instances |
Dynamic Variables | Runtime-typed variables with flexible assignment |
Constant Expressions | Difference between const and readonly |
Key Takeaways
- C# supports various types of variables that can store values and references, from simple types like int to complex reference types like classes.
- const and readonly provide ways to declare variables that should not change after initialization, with const for compile-time constants and readonly for runtime constants.
- var provides type inference, making the code simpler and type-safe while still requiring explicit initialization.
- Nullable types allow value types to be null, and dynamic types provide flexibility with runtime type checking.
- Static variables belong to the class rather than instances, making them shared among all instances, which can be useful for counters or global states within a class.