Hands-On: C# for Beginners
Learn C# from scratch by completing practical exercises, writing real C# code.
Learning C# can feel overwhelming at first. The language is powerful, expressive, and widely used, but for beginners, the syntax alone can look dense and intimidating.
This guide is designed to fix that.
In this complete beginner’s guide to C# syntax, we’ll break down how the language is structured, why it works the way it does, and how the most important syntax elements fit together in real-world software development. Rather than throwing abstract rules at you, we’ll focus on how C# is actually written and read by engineers building production systems.
Whether you’re new to programming or coming from another language, this guide will serve as a practical C# syntax reference you can return to as you learn and grow.
C# (pronounced “C sharp”) is a modern, object-oriented programming language developed by Microsoft. It is most commonly used for:
C# is designed to be:
Understanding C# syntax is the first step toward writing reliable, maintainable software in the .NET ecosystem.
If you’re completely new to the language, starting with a structured introduction, like Dometrain’s Getting Started: C# course, can help reinforce these fundamentals as you learn them in context.
Every C# program follows a clear structure. Even the simplest program includes a few essential elements.
At a high level, a C# program consists of:
A minimal example looks like this:
namespace MyApp;
class Program
{
static void Main()
{
Console.WriteLine("Hello, World!");
}
}
However, since the introduction of top-level statements, you can simply write the following in the Program.cs file and would still be valid C# that works and runs without any issues:
Console.WriteLine("Hello, World!");
You don’t need to understand everything yet. For now, focus on the hierarchy:
Namespace → Class → Method → Statements
This structure is fundamental to C# syntax and will appear in every application you write.
For those new to the ecosystem, setting up a proper development environment is the first step. This guide on setting up your machine for .NET development walks through everything you need to start coding on Windows, macOS, or Linux.
In C#, most instructions are written as statements. Each statement ends with a semicolon (;).
For example:
int score = 100; // Assigning a value
Console.WriteLine(score); // Calling a method
return score; // Returning data
The semicolon tells the compiler where one instruction ends and the next begins. Forgetting it is one of the most common beginner mistakes, and one you’ll quickly learn to spot.
C# is a strongly typed language. That means every variable has a specific type that determines what kind of data it can hold.
A variable declaration includes:
int age = 25;
string name = "Alice";
double price = 19.99;
bool isActive = true;
char grade = 'A';
Common built-in data types include:
Int for whole numbersDouble for decimalsBool for true/false valuesString for text.Strong typing is a core part of C# syntax and helps catch errors early, before your code runs.
C# also supports type inference using the var keyword. This allows the compiler to determine the type automatically based on the assigned value.
var count = 10; // Compiler infers int
var message = "Hello"; // Compiler infers string
var price = 29.99; // Compiler infers double
var isValid = true; // Compiler infers bool
Even when using var, C# remains strongly typed; the type is just inferred instead of explicitly written.
A good rule of thumb: use var when the type is obvious, and explicit types when clarity matters.
Operators allow you to perform actions on values, such as arithmetic, comparison, and logical operations.
Common operator categories include:
int a = 10;
int b = 3;
int sum = a + b; // Addition: 13
int diff = a - b; // Subtraction: 7
int product = a * b; // Multiplication: 30
int quotient = a / b; // Division: 3
int remainder = a % b; // Modulus (remainder): 1
int x = 10;
int y = 5;
Console.WriteLine(x == y); // Equal to: False
Console.WriteLine(x != y); // Not equal to: True
Console.WriteLine(x > y); // Greater than: True
Console.WriteLine(x < y); // Less than: False
Console.WriteLine(x >= 10); // Greater than or equal to: True
Console.WriteLine(x <= 5); // Less than or equal to: False
bool isAdult = true;
bool hasLicense = false;
Console.WriteLine(isAdult && hasLicense); // AND: False (both must be true)
Console.WriteLine(isAdult || hasLicense); // OR: True (at least one is true)
Console.WriteLine(!isAdult); // NOT: False (inverts the value)
Operators are a key part of any C# syntax cheat sheet, as they appear constantly in real code.
Conditional statements allow your program to make decisions.
The if statement evaluates a condition and runs code if the condition is true.
int age = 18;
if (age >= 18)
{
Console.WriteLine("You are an adult.");
}
You can extend this with else if and else blocks to handle multiple scenarios.
int age = 15;
if (age >= 18)
{
Console.WriteLine("You are an adult.");
}
else if (age >= 13)
{
Console.WriteLine("You are a teenager.");
}
else
{
Console.WriteLine("You are a child.");
}
Clear, readable conditionals are essential for maintainable C# code.
When you need to compare a value against multiple possibilities, switch statements are often cleaner than long if chains.
int dayOfWeek = 3;
switch (dayOfWeek)
{
case 1:
Console.WriteLine("Monday");
break;
case 2:
Console.WriteLine("Tuesday");
break;
case 3:
Console.WriteLine("Wednesday");
break;
case 4:
Console.WriteLine("Thursday");
break;
case 5:
Console.WriteLine("Friday");
break;
default:
Console.WriteLine("Weekend");
break;
}
Modern C# also supports switch expressions, which are more concise and expressive.
int dayOfWeek = 3;
string dayName = dayOfWeek switch
{
1 => "Monday",
2 => "Tuesday",
3 => "Wednesday",
4 => "Thursday",
5 => "Friday",
_ => "Weekend"
};
Console.WriteLine(dayName); // Wednesday
Loops allow you to repeat code while a condition is met.
Used when you know how many times you want to iterate.
// for (initializer; condition; iterator)
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"Iteration {i}");
}
// Output:
// Iteration 0
// Iteration 1
// Iteration 2
// Iteration 3
// Iteration 4
Used when the number of iterations isn’t known ahead of time.
int count = 0;
// Loop continues while count is less than 5
while (count < 5)
{
Console.WriteLine($"Count is {count}");
count++; // Increment to eventually exit the loop
}
Used to iterate over collections like lists or arrays.
// Define an array of strings
string[] fruits = { "Apple", "Banana", "Cherry", "Date" };
// foreach iterates over each item in the collection
// 'fruit' is a temporary variable that holds the current item
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
// Output:
// Apple
// Banana
// Cherry
// Date
Foreach is one of the most commonly used loop constructs in modern C#.
Methods are the blocks of code that perform a specific task. They help you:
A method includes:
// Method definition
// ReturnType MethodName(ParameterType parameterName)
static int Add(int a, int b)
{
return a + b; // Returns the sum of a and b
}
// Method with no return value (void)
static void Greet(string name)
{
Console.WriteLine($"Hello, {name}!");
}
// Calling methods from Main
static void Main()
{
// Call method and store the result
int result = Add(5, 3);
Console.WriteLine(result); // Output: 8
// Call void method
Greet("Alice"); // Output: Hello, Alice!
}
If a method doesn’t return a value, it uses the void keyword.
One of the most important concepts to learn after mastering C# syntax is asynchronous programming. This introduction to asynchronous programming in C# explains how “async” and “await” work and why they matter in real applications.
C# is an object-oriented language, and classes are central to its syntax.
A class defines:
// Class definition - a blueprint for creating objects
public class Dog
{
// Properties (data)
public string Name { get; set; }
public int Age { get; set; }
// Method (behavior)
public void Bark()
{
Console.WriteLine($"{Name} says: Woof!");
}
}
// Creating an object (instance) of the class
Dog myDog = new Dog();
myDog.Name = "Buddy";
myDog.Age = 3;
// Calling the method on the object
myDog.Bark(); // Output: Buddy says: Woof!
Objects are created from classes and represent real-world entities or concepts.
Once you’re comfortable with classes and objects, understanding design principles becomes critical. This introduction to SOLID principles in C# shows how good structure builds on clean syntax.
Properties provide a controlled way to access and modify data.
Auto-implemented properties are extremely common in modern C#:
// Class with auto-implemented properties
public class Person
{
// Auto-implemented properties - compiler creates backing fields automatically
public string Name { get; set; } // Can be read and written
public int Age { get; set; } // Can be read and written
public string Email { get; private set; } // Public read, private write
}
// Using properties
var person = new Person();
person.Name = "Alice"; // Setting a property value
person.Age = 30;
Console.WriteLine(person.Name); // Getting a property value - Output: Alice
Properties help enforce encapsulation, a core principle of object-oriented design.
Access modifiers control where code can be accessed from.
Common modifiers include:
publicprivateprotectedInternalpublic class Employee
{
public string Name { get; set; } // Accessible from anywhere
private decimal salary; // Only accessible within this class
protected int employeeId; // Accessible in this class and derived classes
internal string Department { get; set; } // Accessible anywhere in the same project/assembly
public void SetSalary(decimal amount)
{
salary = amount; // Private field accessed within the class
}
}
Choosing the right access level is an important part of writing clean, maintainable C# code.
C# includes powerful tools to handle null values safely.
Modern C# allows you to explicitly indicate whether a variable can be null.
// Enable nullable reference types (usually set in project file)
#nullable enable
string? nullableName = null; // The ? indicates this can be null
string nonNullableName = "Alice"; // This should never be null
// Null check before accessing
if (nullableName != null)
{
Console.WriteLine(nullableName.Length); // Safe - we checked first
}
// Null alternative check
if (nullableName is not null)
{
Console.WriteLine(nullableName.Length); // Safe - we checked first
}
// Null-coalescing operator (??) - provides a default value
string displayName = nullableName ?? "Unknown"; // Returns "Unknown" if null
// Null-conditional operator (?.) - safely access members
int? length = nullableName?.Length; // Returns null instead of throwing exception
// Combine both for safe access with default
int safeLength = nullableName?.Length ?? 0; // Returns 0 if nullableName is null
Safely access members without risking a NullReferenceException.
Person? person = null;
// Without ?. this would throw NullReferenceException
// With ?. it safely returns null instead
string? name = person?.Name;
// Chain multiple accesses safely
int? addressLength = person?.Address?.Street?.Length;
// Works with method calls too
person?.PrintDetails();
Null safety is a critical part of modern C# syntax reference material and helps prevent common runtime errors.
Developers who want to go deeper into this topic often benefit from focused learning, such as Dometrain’s From Zero to Hero: Working with Null in C#, which explores null handling patterns in real-world codebases.
C# provides rich collection types for working with groups of data.
Common collections include:
// Array - fixed size, fast access by index
string[] colors = { "Red", "Green", "Blue" };
Console.WriteLine(colors[0]); // Access by index: "Red"
// List - dynamic size, can add/remove items
List<string> fruits = new List<string>();
fruits.Add("Apple");
fruits.Add("Banana");
fruits.Remove("Apple");
Console.WriteLine(fruits.Count); // 1
// Dictionary - key-value pairs for fast lookups
Dictionary<string, int> ages = new Dictionary<string, int>();
ages["Alice"] = 30;
ages["Bob"] = 25;
Console.WriteLine(ages["Alice"]); // 30
// Iterating over collections
foreach (string color in colors)
{
Console.WriteLine(color);
}
foreach (var pair in ages)
{
Console.WriteLine($"{pair.Key} is {pair.Value} years old");
}
Collections are often paired with loops and LINQ to process data efficiently. Once you’re comfortable with basic syntax, learning LINQ is a natural next step, as it fundamentally changes how you work with collections in C#.
Comments allow you to explain why code exists, not just what it does.
// This is a single-line comment
int score = 100; // Comments can also appear after code
// Use comments to explain WHY, not what
/* This is a multi-line comment
that spans several lines.
Useful for longer explanations
or temporarily disabling code blocks */
int playerLives = 3;
Good comments improve collaboration and long-term maintainability.
Some frequent issues beginners encounter include:
Recognizing these early will save you hours of debugging.
As you start writing more methods, learning how to test them becomes essential. Getting started with unit testing in C# is a great next step for building confidence in your code.
This guide is designed to double as a practical C# syntax cheat sheet and learning resource. As you continue learning, revisit sections when you encounter unfamiliar syntax or concepts.
C# is a deep language, but its syntax is designed to be readable, consistent, and expressive once you understand the fundamentals.
Once you’re comfortable with basic C# syntax, the next steps typically include:
If you’re wondering where C# and .NET can take you long-term, this article on why you should become a .NET developer explores the career opportunities and ecosystem.
Syntax is just the foundation. The real mastery comes when you apply it to real-world problems. This is where structured, project-driven learning, such as Dometrain’s in-depth C# and .NET courses, helps bridge the gap between knowing the syntax and shipping production-ready software.
Learning C# syntax isn’t just about memorizing rules; it’s about understanding how the language expresses ideas.
Focus on clarity, readability, and intent. Write code for humans first, compilers second.
With consistent practice and real-world application, C# becomes approachable and powerful.
© 2026 Dometrain. All rights reserved.