Pustakam Library

Free Programming learning guide

C# for Beginners: A Complete Step-by-Step Guide

C# for Beginners: A Complete Step-by-Step Guide — a free beginner-level guide covering how to learn c# for beginners. Learn with clear explanations,...

101 min read12 chaptersbeginner

What you will learn

  1. Introduction to C# and the .NET Ecosystem
  2. Variables, Data Types, and Basic I/O
  3. Operators and Expressions
  4. Control Flow: Conditional Logic
  5. Control Flow: Loops and Iteration
  6. Methods and Functional Decomposition
  7. Working with Arrays and Collections
  8. Introduction to Object-Oriented Programming (OOP)
  9. OOP: Inheritance and Polymorphism
  10. OOP: Abstraction and Interfaces
  11. Error Handling and Debugging
  12. File I/O and Data Persistence

1. Introduction to C# and the .NET Ecosystem

Your First Step into Software Development Imagine you are writing a letter to a friend who speaks a different language. You have the thoughts in your head (the logic), you write them down in a specific language (the code), but for the friend to understand them, the letter needs to be delivered by a postal service and perhaps translated into a format they can read (the runtime). Programming is exactly like this. You don't just "write code" and magically make a computer do something. There is a sophisticated pipeline that takes your human-readable text and transforms it into electronic pulses that a processor can execute. C (pronounced "C-Sharp") is one of the most popular languages in the world for building everything from mobile apps and high-end 3D games in Unity to massive corporate banking systems. To start using it, you need more than just a text editor; you need an ecosystem. C vs. .NET: Clearing the Confusion One of the most common points of confusion for beginners is the difference between C and .NET. You will often see them mentioned together, but they are fundamentally different things. What is C? C is the programming language. It is a set of rules, keywords, and grammar (called syntax) that humans use to write instructions. If you think of building a house, C is the blueprint. It defines where the walls go and how the plumbing is laid out, but the blueprint itself isn't a house—you can't live inside a piece of paper. What is .NET? .NET (pronounced "dot net") is the framework or platform. It is the massive toolbox and the construction crew that takes the C blueprint and actually builds the house. The .NET ecosystem provides: The Runtime: The engine that actually runs the code on your computer. Class Libraries: A vast collection of pre-written code. For example, instead of writing a complex mathematical formula to calculate a square root from scratch, you use a tool already provided by .NET. The Compiler: The tool that translates your C code into a language the computer understands. Real-World Analogy: Think of C as the English language and .NET as the entire legal system of a country. English is the tool used to write the laws, but the legal system provides the courts, the judges, and the enforcement officers that make those laws actually do something in the real world. How Your Code Actually Runs Computers do not understand C. They only understand binary (1s and 0s). If you fed a C file directly to a CPU, it would have no idea what to do with it. This is where the .NET compilation process comes in. The Two-Step Translation C uses a unique two-step …

2. Variables, Data Types, and Basic I/O

The Memory Box: What is a Variable? Imagine you are organizing a physical office. You have a lot of information—client names, phone numbers, and total invoices—but you can't just throw these pieces of paper onto the floor; you’d never find them again. Instead, you use folders. You label one folder "Client Name," another "Invoice Amount," and another "Is Paid." In C, a variable is exactly like one of those labeled folders. It is a reserved spot in your computer's memory (RAM) used to store a piece of data that your program can refer to, use, and change later. When you create a variable, you are telling the Compiler two critical things: 1. The Name: What you will call this piece of data so you can find it later (e.g., clientName). 2. The Type: What kind of data is allowed to go inside this "folder" (e.g., text, a whole number, or a decimal). Understanding Static Typing C is a statically typed language. This is a fundamental concept that distinguishes it from languages like Python or JavaScript. Static typing means that the data type of a variable is checked and locked in at the moment the code is compiled. Once you declare a variable as an integer (a whole number), it can never hold a string of text. If you try to put a word into a number variable, the Compiler will throw an error before the program even runs. This might seem restrictive, but it is actually a safety feature. It prevents a massive category of bugs—such as trying to mathematically multiply a person's name by their phone number—by catching the mistake while you are still writing the code in your IDE. Common Data Types in C Because the computer needs to know exactly how much memory to allocate for a variable, you must choose the correct data type. Using the wrong type is like trying to put a giant filing cabinet into a small shoebox. Here are the four most common data types you will use as a beginner: 1. int (Integers) The int type is used for whole numbers. These can be positive, negative, or zero, but they cannot have a decimal point. Use case: Counting items, age, years, or loop iterations. Example: 10, -500, 2024. 2. double (Floating-Point Numbers) The double type is used for numbers that require precision, specifically those with fractional parts (decimals). Use case: Prices, GPS coordinates, or scientific measurements. Example: 19.99, -3.14159, 100.0. 3. string (Text) A string is a sequence of characters used to represent text. In C, strings are always enclosed in double quotes (" "). Use case: Names, addresses, or messages to the user. Example: "Hello World", "John Doe", "123 Main …

3. Operators and Expressions

The Engine of Your Program Imagine you are building a simple shopping cart application. You have the price of an item stored in a variable and the quantity the user wants to buy in another. But a program that only stores data is just a digital filing cabinet. To make it useful, the program needs to do something with that data. It needs to multiply the price by the quantity, subtract a discount code, add sales tax, and check if the user has enough balance in their account to complete the purchase. All of these actions—calculating, comparing, and updating—are performed using operators. An expression is simply a combination of variables, constants, and operators that the C compiler evaluates to produce a single value. If variables are the "nouns" of your program, operators are the "verbs." Arithmetic Operators Arithmetic operators are used to perform standard mathematical calculations. C provides a set of symbols that tell the computer which operation to execute. Basic Mathematical Operations The most common operators you will use are: Addition (+): Adds two values together. Subtraction (-): Subtracts the right value from the left value. Multiplication (): Multiplies two values. Division (/): Divides the left value by the right value. Modulo (%): Returns the remainder of a division. The Division Trap: Integer vs. Floating-Point One of the most common hurdles for beginners is how C handles division. The result depends entirely on the Data Types (introduced in Chapter 2) of the numbers involved. If you divide two integers, C performs integer division. This means it throws away the remainder and only keeps the whole number. To get a precise decimal result, at least one of the numbers must be a floating-point type (like double or float): Understanding the Modulo Operator (%) The modulo operator doesn't give you the result of a division; it gives you what is left over. For example, 10 % 3 is 1 because 3 goes into 10 three times, with a remainder of 1. This is incredibly useful for tasks like: Checking for even or odd numbers: A number % 2 that equals 0 is even; if it equals 1, it is odd. Time calculations: Converting total seconds into minutes and remaining seconds. Practical Example: A Simple Invoice Calculator Let's combine these into a real-world scenario. Comparison Operators While arithmetic operators produce numbers, comparison operators produce a Boolean value (true or false). These are used to evaluate the relationship between two values. | Operator | Meaning | Example | Result (if x=5, y=10) | | :--- | :--- | :--- | :--- | | == | Equal to | x == y | false | | != | Not equal to | x != …

4. Control Flow: Conditional Logic

Why Decisions Matter in Code Imagine you're writing a program to greet someone based on their location. In England, you'd say "Hello!", in France "Bonjour!", and in Japan "こんにちは!". Without conditional logic, your program would have to say every greeting at once, which would be confusing and incorrect. Conditional logic allows your program to make decisions, just like you do in real life, and execute different code based on those decisions. In programming, we use control flow to direct how code runs. Control flow is how we tell the computer: "If this condition is true, do this. Otherwise, do something else." This is the foundation of making programs that respond intelligently to different situations. Let’s explore how C gives us the tools to make these decisions. --- Making Decisions with if, else if, and else The simplest way to make a decision in C is with the if statement. It checks whether a condition is true and runs a block of code only if it is. Basic if Statement - The condition temperature 20 evaluates to true because 25 is greater than 20. - So, the message "It's warm outside!" is printed. - If the condition were false, the code inside the curly braces {} would be skipped entirely. 🔤 Key Term: A condition is an expression that evaluates to either true or false. It’s like asking a yes/no question. --- Adding Alternatives with else What if it’s not warm? We can use else to provide a fallback: - Since 15 is not greater than 20, the if block is skipped. - The else block runs instead. - The else keyword doesn’t have a condition—it runs when the if condition is false. --- Multiple Conditions with else if Often, you’ll want to check more than one condition. Use else if to add additional checks: This reads like a natural decision chain: 1. Is it warmer than 20°C? → Print "warm" 2. If not, is it warmer than 15°C? → Print "mild" 3. If neither, print "cool or cold" 💡 Tip: Conditions are checked in order. Once one is true, the rest are skipped. --- Practical Example: Ticket Pricing Let’s apply this to a real-world scenario: a ticket pricing system. - Children under 5 get in free. - People 18 or younger, or who are students, get a discount. - Everyone else pays full price. This uses logical OR (||) to combine conditions: "age <= 18 OR isStudent". --- Combining Conditions: Logical Operators You can build complex decisions by combining conditions using logical operators: | Operator | Name | Meaning | Example | |--------|------|--------|--------| | && | AND | True only if both sides are true | age 18 && hasTicket …

5. Control Flow: Loops and Iteration

Why Loops Matter: The Power of Repetition Imagine you're baking a cake and need to whisk 100 strokes with a hand mixer. Would you count each stroke out loud? Of course not—you'd let the motion become automatic. But what if you had to whisk exactly 100 strokes, no more, no less? You'd need a way to repeat the whisking motion 100 times without losing count. That's precisely what loops do in programming: they let us repeat a block of code a specific number of times or until a certain condition is met. In real life, repetition is everywhere: - A traffic light cycles through red, yellow, green, red... - Your heart beats continuously while you're alive - A coffee machine keeps brewing until the water runs out In programming, loops eliminate the need to write the same code over and over. They make programs concise, readable, and efficient. Without loops, even simple tasks like adding up numbers from 1 to 100 would require writing 100 separate addition statements! Let's explore how C gives us the tools to harness this power of repetition. --- The Anatomy of a Loop Before diving into specific loop types, let's understand the fundamental components that all loops share: 1. The Loop Body This is the block of code that gets repeated. In C, it's typically enclosed in curly braces { }: 2. The Loop Control Mechanism This determines: - How many times the loop runs (counted iteration) - When to stop the loop (condition-based iteration) - When to skip an iteration (using continue) - When to exit entirely (using break) 3. The Loop Variable (in some loops) A variable that tracks the current iteration count or state of the loop. --- Counted Iteration: The for Loop The for loop is perfect when you know exactly how many times you need to repeat something. It's like having a built-in counter that handles the counting for you. Syntax Let's break down each part: | Part | Purpose | Example | |------|---------|---------| | Initialization | Runs once at the start. Typically sets up the loop counter. | int i = 0 | | Condition | Checked before each iteration. If false, loop stops. | i < 5 | | Update | Runs after each iteration. Usually increments the counter. | i++ | Practical Example: Counting Down to Launch What happens here? 1. int seconds = 10 → Start at 10 2. seconds 0 → Keep going while seconds is greater than 0 3. seconds-- → Decrement seconds after each iteration 4. When seconds becomes 0, the condition fails and the loop exits Real-World Example: Calculating Factorials A factorial (n!) is the product of all positive integers up to …

6. Methods and Functional Decomposition

Breaking Down Problems: The Power of Methods Imagine you're writing a short story. You wouldn’t write every sentence without any structure—you’d organize it into paragraphs, chapters, and scenes to make it readable and reusable. Code works the same way. Without organization, even a small program becomes a tangled mess of repeated instructions. That’s where methods come in: they let you break your program into smaller, manageable pieces that do one thing well and can be used again and again. Think of a method like a coffee maker. You don’t need to know how it works internally—just press the button, and coffee comes out. Similarly, you can write a method once, give it a name, and use it anywhere in your program without rewriting the steps. This idea is called functional decomposition: splitting a big problem into smaller, solvable functions. But how do you actually create one? Let’s start from the ground up. --- Why Methods Matter: Reduce, Reuse, Relate Before methods, imagine writing a program that greets three people: Simple enough. But what if you want to greet 50 people? Or change the greeting to "Hi" instead of "Hello"? You’d have to edit every line. That’s repetitive and error-prone. With a method, you define the greeting once: Now you can reuse Greet as often as you like: Same behavior, less work. That’s the power of reusability. 🔍 Real-World Analogy: A recipe is like a method. It defines steps (ingredients, instructions) to make a dish (output). You don’t write the recipe every time you cook—you reuse it. --- Anatomy of a Method Let’s dissect a method line by line. - string → return type: what the method gives back after it runs. - GreetWithTime → method name: how you call it later. - (string name) → parameters: inputs the method expects. - { ... } → method body: the code that runs when the method is called. When you call the method: - "Sam" is the argument—the actual value you pass. - name is the parameter—the variable that receives the value. ⚠️ Common Confusion Alert: Parameter = the variable in the method definition. Argument = the actual value you pass when calling the method. Think: “The method defines the parameter. You provide the argument.” --- Return Types: What Comes Back? Methods can do two things: 1. Perform an action (like print to the screen). 2. Return a result (like calculate the sum of two numbers). If a method doesn’t return anything, its return type is void. This method performs an action but doesn’t give anything back. This method calculates and returns an int. ✅ Best Practice: Use void only when the method’s purpose is to perform an action, not produce a …

7. Working with Arrays and Collections

Storing Lists of Data: The Power of Arrays and Collections Imagine you're writing a program to track the daily temperatures in your city over a week. You could create seven separate variables—one for each day—and update them manually. But what if you needed to store temperatures for a whole year? Or a decade? Creating hundreds or thousands of individual variables would become impossible to manage. This is where arrays and collections come in. They let you group related data together under a single name, making it easy to store, access, and manipulate large amounts of information efficiently. Whether you're working with a fixed set of items (like the days of the week) or a growing list (like customer orders), C provides powerful tools to handle these scenarios. In this chapter, you’ll learn how to declare, initialize, and work with arrays—the simplest way to store multiple items of the same type. Then, you’ll discover collections, which offer more flexibility by allowing dynamic resizing and additional operations. By the end, you’ll be able to store and manage groups of data like a pro, setting the stage for more complex programs in later chapters. --- Understanding Arrays: Fixed-Size Containers for Your Data An array is a collection of variables of the same type that are stored in contiguous memory locations. Think of it like a row of mailboxes in an apartment building: each mailbox has the same size and shape, and they’re all lined up in a single row. You access each one using its index, a number that tells you its position in the row. Declaring and Initializing Arrays To use an array in C, you must first declare it, which means telling the compiler what type of data it will hold and how many items it will store. Then, you initialize it by assigning values to its elements. The basic syntax for declaring an array is: For example, to declare an array that holds integers: This line creates a variable named temperatures that can refer to an array of integers, but it doesn’t yet point to an actual array. To create the array itself (i.e., allocate the memory for it), you use the new keyword: You can also combine declaration and initialization in one step: Here, 7 is the length of the array—the number of elements it can hold. In C, array lengths are fixed at the time of creation. Once an array is created, you cannot change its size. This is a key limitation of arrays, which we’ll address later with collections. You can also initialize an array with values right away: This creates an array of 7 integers with the specified values. The size is inferred from the number …

8. Introduction to Object-Oriented Programming (OOP)

Why Your Code Will Fail Without Object-Oriented Programming Imagine you're writing a simple program to manage a library. You need to track books, patrons, and loans. At first, you might try using separate variables and methods for each book's title, author, and availability. But soon, you'll notice the same problems: - Copy-pasting the same variables for every book becomes tedious. - Updating a book's status requires hunting down every variable that represents it. - Your code turns into a tangled mess, where one change breaks something else. This is where Object-Oriented Programming (OOP) becomes essential. Instead of treating data and behavior as separate pieces, OOP lets you bundle them into objects—self-contained units that model real-world things. A book isn’t just a title and an author; it’s a Book with properties (like availability) and behaviors (like checking out). This approach makes your code cleaner, reusable, and easier to maintain. By the end of this chapter, you’ll understand how to define these objects using classes, create actual instances of them, and control their data with fields, properties, and constructors. --- What Is a Class? The Blueprint for Your Objects A class is like an architectural blueprint. It defines: - What an object will contain (its data or state). - What an object can do (its behaviors or methods). For example, a Book class might specify that every book has: - A title (text data). - An author (text data). - An availability status (true/false data). - A method to check out the book (a behavior). Here’s how you’d define a simple Book class in C: Key Terms: - Class: A template for creating objects. Think of it as a cookie cutter. - Field: A variable that belongs to a class. In the Book example, Title, Author, and IsAvailable are fields. - Method: A function that belongs to a class. Here, CheckOut() is a method. Why Use Classes? - Organization: Group related data and behavior together. - Reusability: Define a class once, and create as many objects (instances) as you need. - Encapsulation: Hide complex details and expose only what’s necessary (we’ll cover this next). --- What Is an Object? Turning a Blueprint into Reality An object is an instance of a class—a concrete realization of the blueprint. If a class is the cookie cutter, an object is the actual cookie. To create an object, you instantiate the class using the new keyword: Now, myBook is an object of type Book. You can set its fields and call its methods: Class vs. Object: The Difference | Class | Object | |-----------|------------| | A blueprint or template. | An actual instance created from the class. | | Defines what an object will have and …

9. OOP: Inheritance and Polymorphism

Real-World Hierarchies: Why Your Dog Isn’t Just a Pet Imagine you’re organizing a family gathering. You have a list of people coming: grandparents, parents, and children. Each group shares certain traits—everyone has a name, an age, and can speak—but each subgroup also has unique behaviors. Grandparents can tell stories, parents can cook meals, and children can play games. If you write this out in code, you wouldn’t duplicate the “name” and “age” fields for every person. Instead, you’d use a structure that allows each subgroup to inherit common traits while adding their own specific ones. This is the power of inheritance in C—a way to build classes that share common code while allowing for specialization. In this chapter, we’ll explore how inheritance lets you create a hierarchy of classes, where child classes extend the behavior of parent classes. We’ll also meet polymorphism, which lets the same method call behave differently depending on the actual object type—just like how the same word “play” means something different when a child says it versus when a grandparent does. --- Building on What You Know: From Classes to Families In [Chapter 8: Introduction to Object-Oriented Programming (OOP)], you learned that a class is a blueprint for creating objects. You created a Person class with properties like Name and Age, and methods like Introduce(). Now, imagine you want to model different types of people at the family gathering: - A Parent who can cook - A Child who can play - A Grandparent who can tell stories Each of these is still a Person, but with added abilities. Instead of writing three separate classes from scratch, you can use inheritance to build on the base Person class. What Is Inheritance? Inheritance is a mechanism in C that allows one class (called the derived class or child class) to inherit the properties and methods of another class (called the base class or parent class). This creates a hierarchical relationship similar to real-world family trees. Think of it like this: - The Person class is the parent. - Parent, Child, and Grandparent are children. - Each child class inherits common traits (like Name and Age) from Person. - Each child can also add or modify behaviors specific to its role. This avoids duplicating code and keeps your program organized and maintainable. --- Creating a Base Class Let’s start with our base class, Person. You’ve already seen something similar, so this will feel familiar. This class defines a basic person with a name and age, and a method to introduce themselves. --- Defining Derived Classes Now, let’s create a Parent class that inherits from Person. Notice the : Person after the class name. This tells C that Parent …

10. OOP: Abstraction and Interfaces

Why Your Car’s Gas Pedal Doesn’t Need to Know How the Engine Works Imagine you’re driving a car. The gas pedal is a simple control: press it, the car moves faster. You don’t need to know how the engine converts fuel into motion—you just trust that pressing the pedal will accelerate the car. That trust is built on abstraction: hiding complex details behind a simple interface. In programming, we use abstraction to hide complexity too. Instead of worrying about how every part of a system works, we define contracts—clear rules that say, “If you implement this, you’ll provide these abilities.” These contracts are called interfaces, and they let us focus on what something does rather than how it does it. In this chapter, you’ll learn how to define and use interfaces, how they differ from abstract classes, and why both tools help you write clean, reusable code. By the end, you’ll see how abstraction makes software easier to design, maintain, and extend—just like how a gas pedal makes driving simpler. --- What Is Abstraction in Programming? Abstraction is the idea of hiding unnecessary details while exposing only the essential features. It’s the reason you don’t need to understand how a microwave works to heat up food—you just press a button labeled “Popcorn.” In programming, abstraction helps us manage complexity. Instead of writing a single massive method that does everything, we break programs into smaller, focused pieces. Each piece has a clear purpose, and we hide how it achieves that purpose. Real-World Analogy: The Light Switch Think of a light switch: - What it does: Turns a light on or off. - How it works: Behind the scenes, it might connect wires, complete a circuit, or send a signal to a smart bulb. You don’t need to know the wiring or the bulb’s internal logic to use the switch. The switch is an abstraction: a simple interface to a complex system. In C, abstraction is achieved through: - Methods: Hide how a task is performed. - Classes: Hide how data is stored and manipulated. - Interfaces and abstract classes: Define what something must do, not how. --- Interfaces: Defining Contracts for Behavior An interface is like a blueprint for behavior. It declares what a class can do, but not how it does it. Syntax: Declaring an Interface - interface is a keyword. - IChargeable is the interface name (by convention, it starts with I). - Charge and GetBatteryLevel are method signatures: they declare what methods must exist, but don’t include any implementation. Why Use Interfaces? Interfaces let you: - Define what a class should do, without dictating how. - Ensure different classes can be used interchangeably if they follow the same …

11. Error Handling and Debugging

Why Your Code Will Break (And How to Fix It) Imagine you’ve spent an entire afternoon writing a program that calculates the total cost of groceries. You type in prices, quantities, and discounts. Everything looks perfect. But when you run it, the program crashes with a scary message like: Suddenly, your screen fills with red text, your confidence drops, and you wonder if programming is really for you. This is the moment where most beginners decide: Is this worth it? The truth is, your code will fail. Not because you’re bad at programming, but because real software runs in an unpredictable world. Users type letters when you expect numbers. Files get deleted. Servers go offline. Networks time out. The list goes on. So the real question isn’t Will my code break? — it’s How will I handle it when it does? This chapter teaches you how to expect the unexpected. You’ll learn how to: - Catch errors before they crash your program - Throw your own custom errors when something goes wrong - Use the Visual Studio debugger to find bugs like a detective - Tell the difference between typos (syntax errors) and hidden traps (runtime errors) By the end, you’ll stop fearing errors and start using them as clues to make your programs more robust and reliable. Let’s begin. --- Understanding Errors: Two Types You Must Know Before you can fix errors, you need to know what kind you're dealing with. Errors in programming fall into two main categories: 1. Syntax Errors: Typos in Your Code A syntax error occurs when you break the grammar rules of C — just like misspelling a word in English. These are caught by the compiler before your program even runs. Examples: - Forgetting a semicolon at the end of a statement - Using = instead of == in a condition - Misspelling a keyword (e.g., Int instead of int) This won’t even compile because the first line is missing a semicolon. The compiler will stop and say: error CS1002: ; expected ✅ You’ll know right away — your code won’t run until you fix it. 2. Runtime Errors: Problems That Happen While Running A runtime error occurs when your code is syntactically correct but tries to do something impossible while the program is running. These are called exceptions. Examples: - Dividing by zero - Trying to read a file that doesn’t exist - Converting the text "Hello" to a number 🛑 This code compiles fine, but when you run it — crash! — your program stops with a DivideByZeroException. Runtime errors are sneaky. They hide in code that looks correct but fails under real-world conditions. 🔍 Think of syntax errors like a …

12. File I/O and Data Persistence

Why Your Data Disappears Imagine you’ve spent three hours building a high-score leaderboard for a game or a contact list for a business application. You’ve used arrays and collections to store all that data perfectly. But then, you close the program. You restart your computer. You open the app again, and everything is gone. This happens because, by default, your program's data lives in RAM (Random Access Memory). RAM is incredibly fast, but it is volatile, meaning it wipes clean the moment the power is cut or the process ends. To make data last, we need Persistence. Data Persistence is the ability of a program to save its state to a non-volatile storage medium—like a Hard Drive or an SSD—so that the information is still there the next time the program runs. In C, we achieve this through File I/O. "I/O" stands for Input/Output: Input is reading data from a file into your program; Output is writing data from your program into a file. The System.IO Namespace C doesn't load every single possible tool into your program by default; doing so would make your applications bloated. Instead, tools are organized into namespaces. To work with files, we need the System.IO namespace. At the top of your code file, you must include: This namespace provides the classes necessary to create, delete, move, and manipulate files and directories (folders). Writing Data with StreamWriter To send text from your program to a file, C provides a class called StreamWriter. Think of a "stream" as a conveyor belt of data. The StreamWriter sits at the end of that belt and pushes the data onto the disk. Basic Writing To write a file, you create an instance of StreamWriter and provide the path to the file you want to create or overwrite. WriteLine(): Writes a string of text followed by a line break (like pressing Enter). Write(): Writes text without adding a line break. Close(): This is critical. It tells the operating system that you are finished with the file, ensuring all data is physically written to the disk and the file is "unlocked" for other programs to use. Resource Management and the 'using' Statement In the previous example, we called writer.Close(). But what happens if an exception (which we covered in Chapter 11) occurs before the code reaches the .Close() line? The file remains "locked" by the operating system, and your program might leak memory. To solve this, C uses the using statement. The using statement ensures that a resource is closed and disposed of automatically as soon as the code block finishes, even if the program crashes. This is called Deterministic Finalization. The Modern 'using' Pattern There are two ways to write this. …

Continue learning