Learn C#.NET Bigginner Level

Learn C#.NET Bigginner Level

.NET

  • .NET doesn't have a full form or definition. It is a software development framework created by Microsoft.

  • Used to create various types of applications like mobile, desktop, web and etc. It supporting over 60 programming languages.

  • It's a language-independent. with Visual Studio as the IDE for development.

Order of Compilation and execution process

C-Sharp Compilation and execution process

Microsoft Intermediate Language (MSIL):

MSIL is a low-level set of instructions created by .NET compilers, like the C# compiler. It translates your C# code but needs another step by the CLR to run on your computer. It handles tasks like Arithmetic Operations, Logical Operations, Data Movement, Control Flow, Method Invocation, Object Creation, Object Manipulation, Exception Handling, and Type Conversion.

It acts as a middle step between the source code and machine code, making the code platform-independent. It serves as a common language for all .NET languages and includes metadata with details about the types, members, and references in the code.

Various types of operations:

  1. Arithmetic Operations: These instructions perform basic mathematical operations. Example instructions include add (addition), sub (subtraction), mul (multiplication), and div (division).

  2. Logical Operations: These instructions handle logical operations used in conditions and bitwise operations. Example instructions include and (logical AND), or (logical OR), xor (logical XOR), and not (logical NOT).

  3. Data Movement: These instructions are used to move data between different locations in memory. Example instructions include ldloc (load local variable), stloc (store local variable), ldarg (load argument), and starg (store argument).

  4. Control Flow: These instructions control the flow of execution in the program, such as jumping to different parts of code based on conditions. Example instructions include br (branch), beq (branch if equal), bne (branch if not equal), brtrue (branch if true), and brfalse (branch if false).

  5. Method Invocation: These instructions are used to call methods and handle method returns. Example instructions include call (call method), callvirt (call virtual method), and ret (return from method).

  6. Object Creation and Manipulation: These instructions manage the creation and manipulation of objects and arrays. Example instructions include newobj (create new object), ldfld (load field), stfld (store field), ldelem (load array element), and stelem (store array element).

  7. Exception Handling: These instructions deal with exceptions and error handling. Example instructions include throw (throw exception), catch (catch exception), and finally (finally block).

  8. Type Conversion: These instructions convert data from one type to another. Example instructions include conv.i4 (convert to int32) and conv.r8 (convert to double).

Common Language Runtime (CLR):

  • Definition: The CLR is a part of the .NET framework that manages the execution of .NET programs. The CLR helps .NET programs run on different operating systems like Windows, Linux, and macOS.

    • In other words, the CLR is like a manager the intermediate code (MSIL) takes generated by .NET compilers and converts it into machine code that your computer can execute.

    • Role: Turns MSIL into machine code, manages memory, handles security, and deals with errors.

  • Characteristics:

    • Execution Environment: Provides the environment where .NET applications run.

    • Service: Includes garbage collection, error handling, and security features.

    • Cross-Language Integration: Allows code written in different .NET languages to work together.

  • Platform Independence:

    • The CLR allows .NET programs to work on different operating systems without changing the code.
  • Implementations:

    • .NET Framework: Works mainly on Windows.

    • .NET Core: Works on Windows, Linux, and macOS.

    • .NET 5+: Combines features of .NET Core and .NET Framework and works on multiple operating systems.

  • How It Works:

    • When you write and compile your .NET code, it turns into MSIL (Microsoft Intermediate Language).

    • The CLR then converts this MSIL into machine code that the computer's hardware can run, no matter what operating system it uses.

The CLR performs several important tasks and includes key components such as:

  1. CLS (Common Language Specification):

    A set of rules that makes sure different .NET languages can work together. It ensures that code written in one language can be used in another.

  2. CTS (Common Type System):

    A standard that defines how data types are used and managed in .NET. It ensures that different .NET languages can share and use data types correctly.

  3. GC (Garbage Collection):

    A system that automatically frees up memory that is no longer needed by your program. This helps prevent memory leaks and keeps your program running smoothly.

  4. JIT (Just-In-Time Compilation):

    A process that converts MSIL code into machine code just before it runs. This makes sure your program runs efficiently on different hardware.

Just-In-Time (JIT) Compiler:

The JIT compiler, part of the CLR, converts MSIL into machine code just before execution, optimizing

  • Characteristics:

    • On-Demand Compilation: Compiles MSIL to machine code at runtime, rather than beforehand.

    • Performance Optimization: Makes the code run faster by optimizing it for the specific hardware.

    • Types of JIT: There are different strategies (like standard JIT, pre-JIT, and EconoJIT) to balance startup time and performance.

Native & machin code:

What is native code and machin code?

  • Native code (understand by OS): Native code is the code that is compiled to run on a specific processor and operating system without the need for further translation or interpretation. Executed directly by the operating system and hardware . Generated by compilers from high-level programming languages and can contain platform-specific optimizations. Format of native code is can include metadata, headers, and other information in addition to the actual machine code (e.g., executables, libraries).

  • Machine code(understand by CPU): Machine code is the simplest form of a program that the computer's CPU can run directly. It is made up of binary instructions that the processor can understand. Executed directly by the CPU . Directly generated from assembly language by an assembler or as an intermediate step by a compiler. Format of machine code is pure binary instructions understood by the CPU.

  • In short, native code is the compiled code that is ready to run on a specific platform, while machine code is the binary instructions that the CPU runs directly. Native code includes machine code and platform-specific details, making it efficient for a particular system.

Dll & Exe file:

  • A .dll (Dynamic Link Library) file contains code and data that can be used by multiple programs simultaneously.

  • And the .exe (Executable) file is a standalone application that can be directly run by the operating system.

  • But the .dll file cannot be directly run, it must be called by an executable (.exe) or another program that uses its functions.

The execution process you outlined

  1. Source Code (.cs)

  2. Compilation

  3. MSIL (in .dll or .exe)

  4. Loading by CLR (with OS support)

  5. JIT Compilation to Native Code (with OS support)

  6. Execution by CPU (managed by OS with CLR services)

+------------------+        +-------------------+       +-----------------+         +---------------+
| Source Code (.cs)| -----> |  Compilation to   | ----->|  Assembly (.dll |  -----> | Execution by  |
|                  |        |      MSIL         |       |     or .exe)    |         |   CLR         |
| (C# Code)        |        | (.NET Compiler)   |       |                 |         |               |
+------------------+        +-------------------+       +-----------------+         +---------------+
                                                                                          |
                                                                                          V
+-----------------------------------------------------------------------------------------+
|                                 Common Language Runtime (CLR)                           |
| +--------------------+      +---------------------+        +-------------------------+  |
| |   Just-In-Time     |      |    Garbage          |        |  Execution Environment  |  |
| |   Compilation      |      |    Collection       |        |  Services (Security,    |  |
| | (Converts MSIL to  |      | (Automatic Memory   |        |  Exception Handling)    |  |
| |  Native Code)      |      |  Management)        |        |                         |  |
| +--------------------+      +---------------------+        +-------------------------+  |
+-----------------------------------------------------------------------------------------+
|
V
+-------------------------+
|       Operating System  |
|  (Memory Management,    |
|  Process Scheduling,    |
|  I/O Operations, etc.)  |
+-------------------------+
                                                                                          |
                                                                                          V
+-------------------------+
|         CPU             |
|   (Executes Native      |
|       Code)             |
+-------------------------+
  1. Source Code (.cs): You write your C# code in files with the .cs extension.

  2. Compilation to MSIL (Microsoft Intermediate Language): The C# compiler (csc.exe) compiles the .cs files into an assembly, which is either a .dll or .exe file containing MSIL, a low-level, platform-independent set of instructions.

  3. Assembly (.dll or .exe): The resulting assembly contains the compiled MSIL code and metadata describing the types, members, and references in the code.

  4. Loading and JIT Compilation by the CLR (Common Language Runtime): When you run the application, the operating system loads the CLR into memory, which then loads the assembly and uses the JIT compiler to translate the MSIL code into native machine code specific to the system's processor architecture.

  5. Execution by the CPU: The CPU directly executes the native machine code within the context provided by the operating system, which handles memory, process scheduling, I/O operations, and other essential services.

  6. Execution Environment and Services Provided by the CLR: The CLR offers services like garbage collection, exception handling, and security checks during execution, relying on the operating system for low-level tasks such as memory management, file access, and network communication.

Explanation of the Role of the Operating System

  • Memory Management: The OS allocates memory for the CLR and the application.

  • Process Management: The OS manages the execution of the application process.

  • I/O Operations: The OS handles input and output operations, such as file access and network communication.

  • System Calls: The CLR and the application make system calls to the OS for various low-level operations.

Beginner Level

What is C#?:

C#.NET (C-Sharp) bellong from C++ background or you say (C# is a extension of C++ language). But C++ only use for build desktop application and (C-Sharp) use to build any type of application.

C# is an object-oriented, modern, general-purpose, type-safe language with a rich standard library and cross-platform capabilities, making it effectively platform-independent.

C# is a Part of the .NET framework or run on .NET Framework.

The 1st version was released in year 2002 by Anders Hejlsberg from Microsoft.

C# is case sensitive language.

C# used for Mobile applications, Desktop applications, Web applications, Web services, Web sites, Games, VR, Database applications, And much, much more!

Basic Syntax and Structure:

Example of 'Hello World' program.

    using System;

        namespace MyApplication
        {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Hello");
            }
        }
    }

using is a keyword which used to import namespace or liberaries. All the class define under the namespacesse's like in their System is namespace.

Namespace like a logical container (logical container mins generaly we group the item's it mins a grouping of files contain by folder and the folder is logical container because file having size and main containe that way we say physical but the folder in Operating System not having any size thay way we say logical ).

In programming language basicaly namespace is also a logiacal container because it's contain classe's or a group of classe's is called namespace.

Namespace is a collection of related class and interfaces.

Bydefault when we create the project the project name is the namespace, you can change also, in this exaple MyApplication is a project name.

class Program: This line mins when we create the project automaticaly one predefine file is created in project and the file name is Program.cs, thats way bydefault one class Program create and name is same as a file name .

class Program it mining i create a class name is Program.

System is a root namespace in C#, in this namespacesse's more than 100 of class containe and by using this using System we consume all classe's.

namespace is a keyword which is uded to create our own namespace.

Main is the Method which is the entry point of C# program. You cannot make more then one Main method in one project's.

Namespace contain class & class contain method and method contain code(source-code).

static: The static keyword in the context of the Main method means that this method belongs to the class itself rather than an instance of the class. This means you can call the Main method without creating an instance of the Program class.

Main Method: The Main method is the entry point of a C# application. It's where the program starts execution. Since it's static, it can be called by the runtime without having to instantiate the Program class.

string[] args is called as command line arguments.

Let's discuss Solutin explorare.

  • File structure in C# NET

    This is Solutin explorare, Why we say solutin explorare because it's root elements. Also IDE say Solution explprer. To open Solutin explorare press ctrl + alt + L.

  • Under Solutin explorare one solution is available and the name is Learn. And Learn solutin contain one project and its name is Learn. You can add multiple project's in Learn Solution.

  • And the project contain one class the name is Program in side Program.cs file.

  • Solution is the collection of Project -> Project is a collection of item's (item's mins lot of things available like classe's, structure, enum, interfasess, windows form's, web form's and etc).

  • Console.WriteLine("Hello"); use to print the statment's, Console is class whic come from System namespace.

  • To create class under the project then you need to add new item (all the things which is in project called new item) then write click on Project and click on add next new item,

    Create new items in c-sharp

  • You change the code inside of MyClass like that to run it.

          using System;
          namespace Learn
          {
              internal class MyClass //It's also a main class because of inside that Main method available.
              {
                  static void Main()
                  {
                      Console.WriteLine("My Second Class !.");
                  }
              }
          }
    
  • But if you want to run this class it give you error, Because we cannot told the Visual Stdio which main class i want to execute, thats way i want to told the visual stdio to run MyClass, Then follow this stape.

  1. Double click on Properties which in your project.

  2. Go to Startup object and next sellect your class.

  3. Run it.

  4. If You want to run any Class you can run it but one thing's are mandatory in side of class Main methid is mandatory.

Data Types

In C-sharp three types of data types.

Value types (int, float, char, double, Byte).

Refrence type (String, array, Object).

Pointer type (int*, char*).

Pointer type is not recommended because it directly interacts with the address of the value.

C# Data Types
  |
  |-- Value Types
  |    |-- Primitive Data Types
  |    |    |-- Integral Types (byte, sbyte, short, ushort, int, uint, long, ulong, char)
  |    |    |-- Floating-Point Types (float, double)
  |    |    |-- Decimal Type (decimal)
  |    |    |-- Boolean Type (bool)
  |    |
  |    |-- Non-Primitive Value Types
  |    |    |-- Structs (custom structs, DateTime, TimeSpan)
  |    |    |-- Enums (custom enums)
  |
  |-- Reference Types (Non-Primitive Types)
  |    |-- Classes (custom classes, String)
  |    |-- Interfaces (custom interfaces)
  |    |-- Arrays (int[], int[,], int[][])
  |    |-- Delegates (custom delegates)
  |    |-- Strings (string)
  |
  |-- Pointer Types (int*, char*)

Variable and Constants:

  • int number = 10;

  • const double PI = 3.14;

  • int x = 5, y = 6, z = 50;

  • int x, y, z; x=y=z=50;

If you want more information about data types, go here:

Comments:

  1. Single-line (//).

  2. Multi-line (/*...*/).

Value Types vs. Reference Types:

Value Types (e.g., int, float, struct): The actual value is stored directly on the stack when they are local variables. Each variable of a value type has its own copy of the data.

Reference Types (e.g., class,objects, array, string,delegate): The reference (pointer) to the data is stored on the stack if it's a local variable, but the actual data is stored on the heap. Variables of reference types share the same data by holding references to the same memory location.

Local variables are variables that are declared within a method, constructor, or block of code (such as within a loop or conditional statement). They are temporary and exist only during the execution of the method or block of code in which they are declared. Once the method or block completes execution, the local variables are destroyed and their memory is released.

If you want to learn more about Stack and Heap Memory, click here:

Type Casting:

One data type to another called Type Casting.

  1. Two types of type casting.

    1. Implicit Casting (Automatic)

      • Performed automatically by the C# compiler when there is no risk of data loss.

      • Example:

              int num = 123;
              long bigNum = num;
        
              float smallNum = 12.34F;
              double largeNum = smallNum;
        
    2. Explicit Casting (Manual)

      • convert one data type to another by manually.

      • Example:

          //Double to int:
              double num = 123.45;
              int intNum = (int)num;
        
          //Long to int:
              long bigNum = 123456789;
              int smallNum  = (int)bigNum;
        
          //String to int:
              string str = "123";
              Convert.ToInt32(str);
        
          //String to double:
              string str = "123.45";
              Convert.ToDouble(str);
        
          //Int to string:
              int myInt = 10;
              Convert.ToString(myInt);
        
  2. This are the all conversion methods:-

    • Convert.ToBoolean(),

    • Convert.ToDouble(),

    • Convert.ToString(),

    • Convert.ToInt32() or int.Parse() ,

    • (int), use to convert only double to int.

        double doubleValue = 3.7;
        int intResult = (int)doubleValue; // intResult will be 3 (truncation)
      
    • Convert.ToInt64() or long.Parse() ,

        string longStr = "9876543210";
        long longValue = Convert.ToInt64(longStr); // longValue will be 9876543210
      
    • (long), Similar to (int), but for long integers (64-bit).

        int intValue = 42;
        long longResult = (long)intValue; // longResult will be 42
      
    • (char), Converts an integer value to Unicode(ASCI) character.

        int charCode = 65; // ASCII code for 'A'
        char character = (char)charCode; // character will be 'A'
      
    • (float) and (double), Convert between floating-point types (single-precision and double-precision)..

        float floatValue = 3.14f;
        double doubleValue = (double)floatValue; // doubleValue will be 3.14
      

User Input:

  • By using Console.ReadLine() to get user Input.

  • Example:

          using System;
          class HelloWorld
          {
              static void Main()
              {
                  string userName;
                  userName = Console.ReadLine();
                  Console.WriteLine("Hello "+ userName+"!");
              }
          }
    

Operators:

  • Arithmetic Operators: (+, -, *, /, %, ++, --);

  • Assignment Operators: (=, +=, -=, *=, /=, %=, &=, !=, |=, ^=, >>=, <<=);

  • Comparison Operators: (==, !=, >, <,>=, <=);

  • Logical Operators: (&&, ||, !);

    Example of &=, |=, ^=, >>= and <<=:

    1. &= (Bitwise AND Assignment):

      • AND operators mins if both are true then true(1) another wize false(0).
            int a = 6;  // binary of 6 is   : 0110
            int b = 3;  // binary of 3 is   : 0011
            a &= b;     // binary result is : 0010 which is 2 binary
            Console.WriteLine(a);  //Output : 2
  1. |= (Bitwise OR Assignmenr):

    • OR operators mins if any one are true(1) then true another wize false(0).
            int a = 6;  // binary of 6 is   : 0110
            int b = 3;  // binary of 3 is   : 0011
            a |= b;     // binary result is : 0111 which is 7 binary
            Console.WriteLine(a);  //Output : 7
  1. ^= (Bitwise XOR Assignment):

    • XOR operators mins if both are opposit diffrent's then true(1) another wize false(0).
            int a = 6;  // binary of 6 is   : 0110
            int b = 3;  // binary of 3 is   : 0011
            a ^= b;     // binary result is : 0101 which is 5 binary
            Console.WriteLine(a);  //Output : 5
  1. >>= (Right Shift Assignment):

    • First convert into binary, Then remove certain number of digits from right side and add the same number of zero(0) in left side.
            int a = 16;  // 16 in binary:00010000
            a >>= 2;     // Shift right by 2 positions: 00000100
            Console.WriteLine(a);  //Output : 4
  1. <<= (Left Shift Assignment):

    • First convert into binary, Then remove certain number of digits from left side and add the same number of zero(0) in right side.
            int a = 4;  // 16 in binary:00000100
            a <<= 2;     // Shift right by 2 positions: 00010000
            Console.WriteLine(a);  //Output : 16
            int a = 4;  // 16 in binary:00000100
            a <<= 3;     // Shift right by 2 positions: 00000000
            Console.WriteLine(a);  //Output : 0

Math:

  • Math.Max(5, 10); //Out: 10 Use to find highest value bitween 2 value.

  • Math.Min(5, 10); //Out: 5 Use to find lowest value bitween 2 value.

  • Math.Sqrt(64); //Out: 8 Use to find square root of value.

  • Math.Abs(-4.7); //Out: 4.7 Use to return absolute value.

  • Math.Round(9.99); //Out: 10 Use to rounds the nearest whole number.

Strings:

String are used for storing text.

  • String contain collection of characters which is surrounded by doubele quotes.

  • Example:string greeting = "Hello Mritunjay Kumar!";.

  • Find length of string: Console.WriteLine(greeting.Length);.

  • Methods:

    1. ToUpper(): Console.WriteLine(greeting.ToUpper());.

    2. ToLower(): Console.WriteLine(greeting.ToLower());.

Concatenation:

  1. Using Operator (+):

         string firstName = "Mritunjay";
         string lastName = " Kumar";
         Console.WriteLine(firstName+lastName);
    
  2. Using string.Concat():

         string firstName = "Mritunjay";
         string lastName = " Kumar";
         Console.WriteLine(string.Concat(firstName,lastName));
    

    Example:

         Console.WriteLine(5 + 2); //Output: 7
         Console.WriteLine('5' + '5'); //Output: 52
         Console.WriteLine("5" + "2"); //Output: 52
         Console.WriteLine(true + true); //Output: Error
    
         Console.WriteLine(String.Concat(5, 2)); //Output: 52
         Console.WriteLine(String.Concat('5', '2')); //Output: 52
         Console.WriteLine(String.Concat("5", "2")); //Output: 52
    
         Console.WriteLine(String.Concat(true, true)); //Output: TrueTrue
    
  3. String Interpolation: (Another method of concatenation by using $ symbole)

         string firstName = "Mritunjay";
         string lastName = "Kumar";
         Console.WriteLine($"My full name is: {firstName} {lastName}"); //Output: My full name is: Mritunjay Kumar
    
  4. Access Strings:

         string firstName = "Mritunjay Kumar";
         Console.WriteLine(firstName[0]); //Output: M
         Console.WriteLine(firstName.IndexOf('i')); //Output: 2
         Console.WriteLine(firstName.IndexOf('e')); //Output: -1
         Console.WriteLine(firstName.IndexOf('M')); //Output: 0
         Console.WriteLine(firstName.IndexOf('m')); //Output: -1
         Console.WriteLine(firstName.IndexOf('y')); //Output: 2
         Console.WriteLine(firstName.IndexOf('x')); //Output: -1
         Console.WriteLine(firstName.IndexOf(' ')); //Output: 9
         Console.WriteLine(firstName.IndexOf('K')); //Output: 10
    
         int a = firstName.IndexOf('K'); //a = 10
         Console.WriteLine(firstName.Substring(a)); //Output: Kumar
    
    • If multiple same character is in there then return 1st character index.
     string firstName = "Mritunjay Kumar Mehata";
     Console.WriteLine(firstName.IndexOf(' ')); //Output: 9
     Console.WriteLine(firstName.IndexOf('M')); //Output: 9

Special Characters:

string txt = "My name is "Mritunjay Kumar"; It's wrong.

string txt = "My name is \"Mritunjay Kumar"; it's correct.

Here's a table that provides basic syntax for working with strings in C#:

OperationSyntaxExample
Single quote (') in a stringUse escape sequence \'string s = "It\'s a test.";
Double quote (") in a stringUse escape sequence \"string s = "He said, \"Hello!\"";
Backslash () in a stringUse escape sequence \\string s = "This is a backslash: \\";
Newline in a stringUse escape sequence \nstring s = "First line\nSecond line";
Tab in a stringUse escape sequence \tstring s = "Column1\tColumn2";
Unicode characterUse escape sequence \u followed by 4-digit hex codestring s = "Unicode: \u263A";
Verbatim string literalUse @ before the stringstring s = @"C:\Program Files";
Interpolated stringUse $ before the stringstring name = "John"; string s = $"Hello, {name}!";

This table summarizes the basic syntax for different string operations in C#.

Booleans:

  • ( YES / NO ), ( ON / OFF ), and ( TRUE / FALSE ).
    bool isFinish = true;
    bool isNotFinish = false;
    Console.WriteLine(isFinish); //Outputs: True
    Console.WriteLine(isNotFinish); //Output: False
    Console.WriteLine(10>9); //Output: True
    Console.WriteLine(10==10); //Output: True
    Console.WriteLine(10==12); //Output: False
    Console.WriteLine(10>=7); //Output: True

if...else if...else: Syntex:

    if (condition)
    {
        //Block of Code
    }else if(condition 2){
        //Block of Code
    }else { 
        //Block of Code
    }

Example:

    int time = 22;
    if (time < 10)
    {
        //Not execute
    }else if(time == 22){
        //Execute
    }else { 
        //Not execute
    }

Ternary Operator:

Syntex:

    variable = condition ? executeTruePartOfCode : executeFalsePartOfCode;

Example:

    Console.WriteLine((2>1)?"2 is gratter":"1 is gratter");

Switch Case:

  • The switch statement works with various types of variables including int, char, string, bool and enums. It also supports pattern matching.

  • Each case label must be a constant value.

  • You cannot have duplicate case labels in the same switch statement.

  • Each case label ends with a colon (:).

  • Each case typically ends with a break statement another wize it go to the next case.

  • The default case is optional but recommended.

  • It executes if none of the other cases match the switch expression.

  • Syntex:

          switch(expression) 
          {
            case x:
              // code block
              break;
            case y:
              // code block
              break;
            default:
              // code block
              break;
          }
    
  • Example:

          int day = 4;
          switch (day) 
          {
            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;
            case 6:
              Console.WriteLine("Saturday");
              break;
            case 7:
              Console.WriteLine("Sunday");
              break;
          }
          // Outputs "Thursday" (day 4)
    
  • C# 7.0 introduced pattern matching, allowing more complex conditions in switch statements.

  • Example:

          string command = "start";
          switch (command)
          {
              case "start":
                Console.WriteLine("Starting");
                break;
              case "stop":
                Console.WriteLine("Stopping");
                break;
              case "pause":
                Console.WriteLine("Pausing");
                break;
              default:
                Console.WriteLine("Unknown command");
                break;
          }
    

Example: Type Pattern Matching with switch:

  • If obj is an int, the value is assigned to the variable i, and the corresponding block is executed, printing the integer value.

  • If obj is a string, the value is assigned to the variable s, and the corresponding block is executed, printing the string value.

  • If obj is null, the corresponding block is executed, printing "Null".

          object obj1 = "Hello";
          switch (obj1)
          {
              case int i:
                  Console.WriteLine($"Integer: {i}");
                  break;
              case string s when s.Length > 5:
                  Console.WriteLine($"Long string: {s}");
                  break;
              default:
                  Console.WriteLine("Other type or shorter string");
                  break;
          }
    

Example: Pattern Matching with Additional Conditions:

  • If obj1 is an int, the value is assigned to the variable i, and the corresponding block is executed, printing the integer value.

  • If obj1 is a string and its length is greater than 5, the value is assigned to the variable s, and the corresponding block is executed, printing the string value.

          object obj1 = "Hello";
          switch (obj1)
          {
              case int i:
                  Console.WriteLine($"Integer: {i}");
                  break;
              case string s when s.Length > 5:
                  Console.WriteLine($"Long string: {s}");
                  break;
              default:
                  Console.WriteLine("Other type or shorter string");
                  break;
          }
    

Example: Switch Expression:

  • Introduced in C# 8.0, which provides a more concise syntax for assigning a value based on the matched case.

  • The switch expression evaluates the value of variable and matches it against the specified patterns.

  • The underscore _ serves as a wildcard pattern that matches any value not covered by the previous cases. The expression evaluates to "Default result".

  • The result variable will be assigned the value corresponding to the matched case. This approach simplifies the assignment logic compared to a traditional switch statement.

          var result = variable switch
          {
              value1 => "Result for value1",
              value1 => "Result for value2",
              _ => "Default result",
          };
    
          int variable = 1;
          var result = variable switch
          {
              1 => "Result for value1",
              2 => "Result for value2",
              _ => "Default result",
          };
          Console.WriteLine(result);
    

While Loop:

  • Syntax:

          while(condition)
          {
              //Code block
          };
    
  • Example:

          int i = 1;
          while(i<5)
          {
              Console.WriteLine(i);
              i++;
          };
    

do While Loop:

  • Syntax:

          do
          {
              //Code block
          } while(condition);
    
  • Example:

          int i = 1;
          do
          {
              Console.WriteLine(i);
              i++;
          }while(i<5);
    

For Loop:

  • Syntax:

          for (statement 1; statement 2; statement 3) 
          {
            // code block to be executed
          }
    
  • Example:

          for (int i = 0; i < 5; i++) 
          {
            Console.WriteLine(i);
          }
    

Nested Loop:

  • Example:

          // Outer loop
          for (int i = 1; i <= 2; ++i) 
          {
            Console.WriteLine("Outer: " + i);  // Executes 2 times
            // Inner loop
            for (int j = 1; j <= 3; j++) 
            {
              Console.WriteLine(" Inner: " + j); // Executes 6 times (2 * 3)
            }
          }
    

Foreach loop:

  • There is also a foreach loop, which is used exclusively to loop through elements in an array:

  • Syntax:

          foreach (type variableName in arrayName) 
          {
            // code block to be executed
          }
    
  • Example:

          string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
          foreach (string i in cars) 
          {
            Console.WriteLine(i);
          }
    

Break & Continue:

  • The break statement used to jump out of a loop.

  • The continue statement breaks one iteration (in the loop), if a specified condition occurs, and continues with the next iteration in the loop.

GOTO Statments:

  • The goto statement is used to jump to a specific part of the code.

How to Use:

  1. Label: First, you create a label in your code. A label is a name followed by a colon (:).

  2. Jump: Then, you use goto to jump to that label.

Example:

using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("Start");

        goto JumpHere; // Jump to the label

        Console.WriteLine("This will be skipped");

        JumpHere: // Label
        Console.WriteLine("End");
    }
}

Explanation:

  • "Start" is printed first.

  • goto JumpHere; tells the program to jump to the label JumpHere.

  • The line Console.WriteLine("This will be skipped"); is skipped.

  • The label JumpHere: marks where the program continues, so "End" is printed next.

Caution:

  • Using goto can make your code hard to read and understand. It's better to use loops and other control structures when possible.

Array:

Array is collection of homogeneous data items. It allows you to store multiple values in a single variable, and you can access each item using an index. Basically we have three types of arrays.

  1. Single dimension;

  2. Multiple dimension;

  3. Jagged array;

Syntex of Array:- <data type>[] <array name>=new <data type> [size]; .

Rank specifier is used to specify the dimension of array.

  • [ ] - one dimension array.

  • [,] - two dimension array.

  • [,,] - three dimension array /multi dimension array.

  • [ ][ ] - Jagged array (array of arrays).

Advantages of Arrays:

  1. Searching and sorting: By using array we can easily perform searching and sorting.

  2. Efficient Storage: Arrays let you store multiple values in one variable, making it easier to manage data. Array is a user defined data type which is used to store multiple values of single variable of same data type.

  3. Easy Access: You can quickly access any item using its index.

  4. Memory Management: Arrays can help in managing memory efficiently since they store data in contiguous memory locations.

  5. Better Performance: Accessing elements by index is fast, which can improve performance in certain applications.

  6. Simplified Code: Using arrays can make your code cleaner and easier to understand when dealing with multiple related values.

  7. Index: Index of the array will always, with 0 and ends with (size -1).

To declare an array, define the variable type with square brackets: string[] cars; ..

We have now declared a variable that holds an array of strings.

To insert values to it, we can use an array literal - place the values in a comma-separated list, inside curly braces: string[] cars = {"Volvo", "BMW", "Ford", "Mazda"}; .

To create an array of integers, you could write: int[] myNum = {10, 20, 30, 40}; .

Access the Elements of an Array: You access an array element by referring to the index number like that string[] cars = {"Volvo", "BMW", "Ford", "Mazda"}; Console.WriteLine(cars[0]); // Outputs Volvo .

Change an Array Element: To change the value of a specific element, refer to the index number like cars[0] = "Opel"; .

Array Length: To find out how many elements an array has, use the Length property like that Console.WriteLine(cars.Length); .

Example:-

using System;

namespace Array
{
    internal class Program
    {
        static void Main(string[] args)
        {
            //Declear array:- 
            int[] num = new int[] {2,1,4,5,6,7};
            Console.WriteLine("2: "+num[2]);
            foreach (int i in num)
            {
                Console.WriteLine(i);
            }

            //Inslize the value in array:-
            int[] num1 = new int[5];
            Console.WriteLine("Enter 5 elements:-");
            for (int i = 0; i< num1.Length; i++)
            {
                Console.WriteLine($"Enter the {i} elements: ");
                num1[i] = Convert.ToInt32(Console.ReadLine());
            }

            //Printing the value of array:- 
            Console.WriteLine("All Enter element's: ");
            for (int i = 0; i < num1.Length; i++)
            {
                Console.WriteLine(num1[i]);
            }
            Console.ReadKey();
        }
    }
}

Pass refren to coppy the array:

using System;

namespace Practical_Exercises
{
    class Program2
    {
        static void Main()
        {
            Console.WriteLine("Array:- ");
            int[] arr = new int[] { 1, 2, 3, 4, 5 };
            int[] arr2 = new int[5];

            Console.WriteLine("Befor doing any things");
            foreach (int i in arr ) Console.Write(i+" ");//1 2 3 4 5
            Console.WriteLine();
            foreach (int i in arr2 ) Console.Write(i+" ");//0 0 0 0 0

            Console.WriteLine("\nCopy or pass refrence");
            arr2 = arr;//Pass refrence of arr to arr2 (refrence mins first element index address pass arr to arr2).    
            foreach (int i in arr) Console.Write(i + " ");//1 2 3 4 5
            Console.WriteLine();
            foreach (int i in arr2) Console.Write(i + " ");//1 2 3 4 5

            Console.WriteLine("\nChange the value of arr then automaticly change arr2");
            arr[2] = 58;
            foreach (int i in arr) Console.Write(i + " ");//1 2 3 4 5
            Console.WriteLine();
            foreach (int i in arr2) Console.Write(i + " ");//1 2 3 4 5
            Console.ReadLine();
        }
    }
}

In that example, one problem is that when we change any value in array of arr, the value in arr2 automatically changes because we pass the reference of arr to arr2. This means we pass the address of the first element of arr to arr2, and arr2 gets the address of the first element and accesses all the array values. The reference is stored in stack memory, while all the array values are stored in heap memory.

Convert String to Character Array:

string str = "Mritunjay Kumar";
char[] c = str.ToCharArray();//{'M','r','i','t','u','n','j',}

Convert char array back to string:

string newStr = new string(c);

Syntex:

  1. Single dimension:- A single-dimensional array is the simplest form of an array. It's like a list of items arranged in a sequence.

    Syntex: datatype[ ] anyname = new datatype [size]; .

    Example:

     //Example 1:
     int[] numbers = new int[5]; // Create an array of five elements, and add values later    
     numbers[0] = 10;
     numbers[1] = 20;
     numbers[2] = 30;
     numbers[3] = 40;
     numbers[4] = 50;
     //Example 2:
     // Create an array of four elements and add values right away 
     string[] cars = new string[4] {"Volvo", "BMW", "Ford", "Mazda"};
    
     //Example 3:
     // Create an array of four elements without specifying the size 
     string[] cars = new string[] {"Volvo", "BMW", "Ford", "Mazda"};
    
     //Example 4:
     // Create an array of four elements without using the new keyword and without specifying the size.   
     string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
    
  2. Multi dimension:- A multi-dimensional array can be thought of as a table or a grid, where data is stored in rows and columns.

    Syntex: datatype[,] anyname = new datatype[rows size, columns size]; .

    Example of 2 dimension array:

    Declear and Printing value:

     using System;
     using System.Collections.Generic;
     using System.Linq;
     using System.Text;
     using System.Threading.Tasks;
    
     namespace Method
     {
         internal class TwoDArray
         {
             static void Main(string[] args)
             {
                 //Initialisation of two dim array
                 int[,] numbers = new int[,] { { 10, 20, 30 }, { 40, 50, 60 } };
                 Console.WriteLine("Two Dim array elements are");
                 int i, j;
                 for (i = 0; i < 2; i++)
                 {
                     for (j = 0; j < 3; j++)
                     {
                         Console.Write(numbers[i, j] + "\t");
                     }
                     Console.WriteLine("\n");
                 }
                 Console.ReadKey();
             }
         }
     }
    

    Initialisation Value:

     //Example 1:
     // Create a 2D array with 3 rows and 3 columns, and add values later
     int[,] matrix = new int[3, 3];
     matrix[0, 0] = 1;
     matrix[0, 1] = 2;
     matrix[0, 2] = 3;
     matrix[1, 0] = 4;
     matrix[1, 1] = 5;
     matrix[1, 2] = 6;
     matrix[2, 0] = 7;
     matrix[2, 1] = 8;
     matrix[2, 2] = 9;
    
     //Example 2:
     // Create and initialize a 2D array with values right away
     int[,] matrix = new int[3, 3] {
         {1, 2, 3},
         {4, 5, 6},
         {7, 8, 9}
     };
    
     //Example 3:
     // Create and initialize a 2D array without specifying the size
     int[,] matrix = {
         {1, 2, 3},
         {4, 5, 6},
         {7, 8, 9}
     };
    

    Accepting elements from user:-

     using System;
     namespace Method
     {
         internal class TwoDArray
         {
             static void Main(string[] args)
             {
                 //Accepting value from user of two dim array
                 int[,] numbers = new int[2,2];
                 Console.WriteLine("Two Dim array elements are");
                 int i, j;
                 for (i = 0; i < 2; i++)
                 {
                     for (j = 0; j < 2; j++)
                     {
                         numbers[i,j] = Convert.ToInt32(Console.ReadLine());
                     }
                 }
                 Console.ReadKey();
             }
         }
     }
    

    Three Dim Arrays or Multi Dim arrays:

    Example:- Int [,,] numbers = new int [2,3,2];

    2 - Semesters, 3 - Subjects, 2 - Papers

     using system;
    
     namespace ThreeDimArray
     {
         class Program
         {
             static void Main(string[] args)
             {
                 //three dim array demo1
                 // 2 semesters, 3 subjects and 2 papers
                 int[,,] marks = new int[2, 3, 2];
                 int i, j, k;
                 Console.WriteLine("enter marks in 12 subjects :");
                     for(i=0;i<;2;i++)//sems
                     {
                         Console.WriteLine("enter marks for Sem "+(i+1));
                         for(j=0;j<;3;j++)//subjects
                         {
                             if(j==0)
                                 Console.WriteLine(" Maths ");
                             else if(j==1)
                                 Console.WriteLine(" Physics ");
                             else
                                 Console.WriteLine(" Chemistry ");
                             for(k=0;k<;2;k++)// papers
                             {
                                 if(k==0)
                                     Console.Write(" Paper 1: ");
                                 else
                                     Console.Write(" Paper 2:");
                                 marks[i, j, k] = Convert.ToInt32(Console.ReadLine());
                             }//end of papers
                         }//end of subjs
                     }//end of sems
                 Console.ReadKey();
             }
         }
     }
    
  3. Jagged Array:- An array of arrays, where each sub-array can be of different size. The inner arrays can have different sizes. Where each element can have a different size. It's useful when the inner arrays don't need to be of the same size.

    Jagged arrays are also called as Array of Arrays. We can also call them as Two dim arrays with varying columns.

    Syntex: datatype[][] arrayName = new datatype[size][];

    Example:- .

     static void Main(string[] args)
     {
     //working with Jagged Arrays
     int[][] marks = new int[4][];
     marks[0] = new int[] {10,20,30,40 };
     marks[1] = new int[] { 10, 20, 30, 40,50,60 };
     marks[2] = new int[] { 10, 20, 30 };
     marks[3] = new int[] { 10, 20, 30, 40,50,60,70,80 };
     Console.WriteLine("Jagged Array elements are :");
     for(int i=0;i&lt;4;i++)
     {
         for(int j=0;j&lt;marks[i].Length;j++)
         {
             Console.Write(marks[i][j]+&quot;,&quot;);
         }
         Console.WriteLine();
     }
     Console.ReadKey();
    
     }
    

    Example:

     //Example 1:
     // Create a jagged array with 3 elements, and initialize the inner arrays later
     int[][] jaggedArray = new int[3][];
     jaggedArray[0] = new int[2]; // First inner array with 2 elements
     jaggedArray[1] = new int[3]; // Second inner array with 3 elements
     jaggedArray[2] = new int[1]; // Third inner array with 1 element
    
     jaggedArray[0][0] = 1;
     jaggedArray[0][1] = 2;
     jaggedArray[1][0] = 3;
     jaggedArray[1][1] = 4;
     jaggedArray[1][2] = 5;
     jaggedArray[2][0] = 6;
    
     //Example 3:
     // Create and initialize a jagged array right away
     int[][] jaggedArray = new int[][] {
         new int[] {1, 2},    // First inner array with 2 elements
         new int[] {3, 4, 5}, // Second inner array with 3 elements
         new int[] {6}        // Third inner array with 1 element
     };
    
     //Example 4:
     // Create and initialize a jagged array without specifying the size
     int[][] jaggedArray = {
         new int[] {1, 2},    // First inner array with 2 elements
         new int[] {3, 4, 5}, // Second inner array with 3 elements
         new int[] {6}        // Third inner array with 1 element
     };
    

Define the Array size at runtime:

//1D Array:
int size = 10; // Size determined at runtime
int[] array1D = new int[size];

//2D Array:
int rows = 3; // Number of rows determined at runtime
int columns = 4; // Number of columns determined at runtime
int[,] array2D = new int[rows, columns];

//3D Array:
int dim1 = 2; // Size of the first dimension determined at runtime
int dim2 = 3; // Size of the second dimension determined at runtime
int dim3 = 4; // Size of the third dimension determined at runtime
int[,,] array3D = new int[dim1, dim2, dim3];

//Jagged Array:
int outerSize = 3; // Size of the outer array determined at runtime
int innerSize1 = 2; // Size of the first inner array determined at runtime
int innerSize2 = 4; // Size of the second inner array determined at runtime
int innerSize3 = 3; // Size of the third inner array determined at runtime

// Define the outer array
int[][] jaggedArray = new int[outerSize][];

// Initialize each inner array with different sizes
jaggedArray[0] = new int[innerSize1];
jaggedArray[1] = new int[innerSize2];
jaggedArray[2] = new int[innerSize3];

Single-Dimensional Array: A simple list of items arranged in a sequence.

Multi-Dimensional Array: A table or grid of items with rows and columns.

Jagged Array: An array of arrays where each inner array can be of different sizes.

Loop an Array:

  • Using for loop:
    string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
    for (int i = 0; i < cars.Length; i++) 
    {
      Console.WriteLine(cars[i]);
    }
  • Using foreach loop:

    • Syntex:
        foreach (type variableName in arrayName) 
        {
          // code block to be executed
        }
  • Example:
        string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
        foreach (string i in cars) 
        {
          Console.WriteLine(i);
        }
        //foreach also work in string.

What is the difference between array and jagged array in C#?

  • Ans: In a multidimensional array, each element in each dimension has the same, fixed size as the other elements in that dimension. In a jagged array, which is an array of arrays, each inner array can be of a different size.

Drawbacks of arrays.

  1. We cannot store different types of elements in an array.

  2. We cannot change the size of an array (we cannot increase or decrease it).

  3. If we store fewer elements, it leads to wasted memory.

  4. An array is also called static memory allocation.

  5. Inserting an element into an existing array is difficult. We need to write logic to move the existing elements to the next cells.

  6. Removing an element also requires logic to move the elements to the previous cells.

Memory Allocation:

  • Arrays are reference types in C#.

  • The reference to the array is stored on the stack if the array is a local variable.

  • The actual array data (the elements of the array) is stored on the heap.

Example:

public void ExampleMethod()
{
    int[] numbers = new int[5]; // Array of integers
    numbers[0] = 10;
    numbers[1] = 20;
    // and so on...
}
  • Reference to the Array:

    • numbers is a reference to an array.

    • Since numbers is a local variable, the reference to the array is stored on the stack.

  • Actual Array Data:

    • The actual array (the block of memory that can hold 5 integers) is allocated on the heap.

    • The values 10, 20, and so on are stored within this block of memory on the heap.

  • Diagram for Clarity:

    • simplified diagram to illustrate the memory allocation:

    •                                                                   Stack:
                                                                        +--------------------+
                                                                        | numbers (reference)| ------> +-------------------+
                                                                        |                    |         |  [0] = 10         |
                                                                        |                    |         |  [1] = 20         |
                                                                        |                    |         |  [2] = 0          |
                                                                        |                    |         |  [3] = 0          |
                                                                        |                    |         |  [4] = 0          |
                                                                        +--------------------+         +-------------------+
      

      The numbers variable, which is a reference to the array, is stored on the stack. The actual array with its elements is stored on the heap.

  • The reference to the array is stored on the stack (if the array is a local variable).

  • The actual data (the elements of the array) is stored on the heap.

The difference between the two array declarations is the following:

  • Implicitly Typed Array Initialization:

      string[] s = { "Mritunjay", "Kumer" };
    
    • In this case, the array s is declared and initialized using an array initializer.

    • The type of the array (string[]) is explicitly declared.

    • The compiler infers the size of the array based on the number of elements provided in the curly braces.

    • The compiler automatically translates this to an array creation with the new keyword behind the scenes and converts it to new string[] { "Mritunjay", "Kumer" }.

  • Explicitly Typed Array Initialization:

      string[] s1 = new string[] { "Mritunjay", "Kumer" };
    
    • Here, the array s1 is declared and initialized using the new keyword and an array initializer.

    • The type of the array (string[]) is explicitly declared, and the array is explicitly created using the new keyword.

    • This form is more explicit about the array creation.

Key Differences:

  • Syntax:

    • The first form is shorter and more concise.

    • The second form is more explicit about the array creation process.

  • Usage:

    • Both forms achieve the same result: creating and initializing an array with the specified values.

    • The choice between them is mostly a matter of style and preference. The first form is often used for simplicity and conciseness, while the second form may be preferred for its explicitness, especially in more complex scenarios where clarity is important.

Methods:

  • A method is a block of code which only runs when it is called.

  • You can pass data, known as parameters, into a method.

  • Methods are used to perform certain actions, and they are also known as functions.

  • Why use methods? To Code Reusability: define the code once, and use it many times. Organization: Break down complex problems into smaller, manageable pieces. Maintainability: Easier to update and fix code. Readability: Makes code easier to understand by giving descriptive names to actions.

  • When to use Methods? Use methods when you have a task or logic that you will need to perform multiple times or when you want to organize your code into logical sections.

  • Method is a group of statements having a name used for a specific purpose. It may or may not return a value.

Methods are of two types:

  1. Pre-defined methods (Built-in) : These are given by C#

  2. User defined methods: We need to define our own methods.

In a predefined method, the method definition includes the method name, parameters, and return type.

How Methods Work:

  1. Definition: Define a method with a name, parameters (optional), and a return type (optional).

  2. Calling: Call the method from other parts of the program to execute its code.

Method Syntax:

returnType MethodName(parameters)
{
    // Method body
    // Code to execute
    return value; // if the return type is not void
}

Or:

<Access Modifier><Return Type><Method Name>(Parameter list)
{
    //Body of Method
    //Code to Be Executed
}

Example:-

static void Hello()
{
    Console.WriteLine("Hello world");
}
  • Method name: Hello

  • Return type : void (not returning any value)

  • Parameters : no parameters

Note: If return type is void then we need not return any value from a method. Other than void if you write like int,string,double,bool etc. we have to write return statement.

Create a Method:

A method is defined with the method's name, followed by parentheses (). C# has some built-in methods, like Main(), but you can also create your own methods to do specific tasks:

Create a method inside the Program class:

class Program
{
  static void PrintHello() 
  {
    // code to be executed
  }
}
  • PrintHello() is the name of the method.

  • static means that the method belongs to the Program class and not an object of the Program class. You will learn more about objects and how to access methods through objects lets discuss.

Call a Method:

  • To call (execute) a method, write the method's name followed by two parentheses () and a semicolon**;**

  • In the following example, PrintHello() is used to print a text (the action), when it is called.

  • Inside Main(), call the PrintHello() method:

      static void PrintHello() 
      {
        Console.WriteLine("I just got executed!");
      }
    
      static void Main(string[] args)
      {
        PrintHello();
      }
    
      // Outputs "I just got executed!"
    
  • A method can be called multiple times:

      static void PrintHello() 
      {
        Console.WriteLine("I just got executed!");
      }
    
      static void Main(string[] args)
      {
        PrintHello();
        PrintHello();
        PrintHello();
      }
    
      // I just got executed!
      // I just got executed!
      // I just got executed!
    

Detailed Examples:

Example 1: A Simple Method

// A method that greets a user
void Greet(string name)
{
    Console.WriteLine("Hello, " + name + "!");
}

// Calling the Greet method
Greet("Alice"); // Outputs: Hello, Alice!

Example 2: Method with Return Type

// A method that calculates the square of a number
int Square(int number)
{
    return number * number;
}

// Calling the Square method
int squareOfFive = Square(5); // Outputs: 25
Console.WriteLine(squareOfFive); // Outputs: 25

Example 3: Method Overloading

// Method overloading: same method name with different parameters
void Display(int number)
{
    Console.WriteLine("Number: " + number);
}

void Display(string text)
{
    Console.WriteLine("Text: " + text);
}

// Calling overloaded methods
Display(10); // Outputs: Number: 10
Display("Hello"); // Outputs: Text: Hello

Advantages of Methods:

  • Modularity: Divide complex tasks into smaller methods.

  • Reusability: Use the same method in different parts of the program.

  • Readability: Easier to read and understand code.

  • Maintainability: Easier to fix and update code since you only need to change the method definition.

Disadvantages of Methods

  1. Overhead: Calling methods can add a small overhead, especially if methods are called very frequently in performance-critical code.

  2. Complexity: Too many small methods can make the codebase more complex and harder to follow.

  3. Dependency: Methods that depend on other methods or global state can be hard to debug and maintain.

Parameters and Arguments:

  • Information can be passed to methods as parameters. Parameters work like variables inside the method.

  • They are listed after the method name, inside the parentheses. You can add as many parameters as you need, just separate them with a comma.

  •     static void PrintHello(string fname)
        {
            Console.WriteLine(fname);
        }
    
        static void Main(string[] args)
        {
            PrintHello("Mritunjay");
            PrintHello("Student");
        }
    
        // Mritunjay
        // Student
    
  • This method that takes a string called fname as parameter. When the method is called, we pass along a first name, which is used inside the method to print the full name.

  • When a parameter is passed to the method, it is called an argument. So, from the example above: fname is a parameter, while Mritunjay and Student are arguments.

Multiple Parameters :

You can have as many parameters as you like, just separate them with commas.

Example:-

static void MyMethod(string fname, int age) //fname and age are argument
{
  Console.WriteLine(fname + " is " + age);
}

static void Main(string[] args)
{
  MyMethod("Liam", 5); //Liam and 5 are parameters.
  MyMethod("Jenny", 8);
  MyMethod("Anja", 31);
}

// Liam is 5
// Jenny is 8
// Anja is 31

Note that when you use multiple parameters, the method call must have the same number of arguments as there are parameters, and the arguments must be in the same order.

Note: When you use multiple parameters to call method, the number of parameters and the number of arguments are same and must be in the same order's.

Use Default Parameter Value:

You can also use a default parameter value, by using the equals sign (=).

If we call the method without an argument, it uses the default value ("Apple"):

using System;

class Program
{
    static void PrintFruit(string fruit = "Apple")
    {
        Console.WriteLine(fruit);
    }

    static void Main(string[] args)
    {
        PrintFruit("Banana");
        PrintFruit("Orange");
        PrintFruit();
        PrintFruit("Mango");
    }
}
//Banana
//Orange
//Apple
//Mango

A parameter with a default value is known as an "optional parameter".

Named Arguments:

It is also possible to send arguments with the key: value syntax. That way, the order of the arguments does not matter:

Example:

static void MyMethod(string child1, string child2, string child3) 
{
  Console.WriteLine("The youngest child is: " + child3);
}

static void Main(string[] args)
{
  MyMethod(child3: "John", child1: "Liam", child2: "Liam");
}

// The youngest child is: John

Return Values:

Methods with return values are a fundamental concept in C# programming, allowing for modular, reusable, and clear code. They perform tasks and send back results to the calling code, enhancing the flexibility and functionality of programs. Proper handling of return values is essential for effective and error-free coding.

This means that after performing their task, they can send a value back to the place where they were called. This is useful for getting results from computations or operations performed within the method.

If you want the method to return a value, you can use a primitive data type (such as int or double) instead of void, and use the return keyword inside the method. Use the return keyword followed by the value you want to return.

using System;

class Program
{
    // Method to add two numbers and return the result
    static int Add(int a, int b)
    {
        return a + b;
    }

    // Method to concatenate two strings and return the result
    static string Concatenate(string str1, string str2)
    {
        return str1 + str2;
    }

    // Method to check if a number is even and return the result
    static bool IsEven(int number)
    {
        return number % 2 == 0;
    }

    static void Main(string[] args)
    {
        // Calling the Add method and storing the result
        int sum = Add(5, 3);
        Console.WriteLine("Sum: " + sum); // Outputs: Sum: 8

        // Calling the Concatenate method and storing the result
        string combinedString = Concatenate("Hello, ", "World!");
        Console.WriteLine("Combined String: " + combinedString); // Outputs: Combined String: Hello, World!

        // Calling the IsEven method and storing the result
        bool isEightEven = IsEven(8);
        Console.WriteLine("Is 8 Even? " + isEightEven); // Outputs: Is 8 Even? True
    }
}

/*
Sum: 8
Combined String: Hello, World!
Is 8 Even? True
*/

Advantages of Methods with Return Values

  1. Modularity: Encapsulate logic and computations in reusable methods.

  2. Reusability: Methods can be called multiple times and used in different contexts.

  3. Clarity: Clear separation of tasks and results.

  4. Flexibility: Methods can return various data types based on the need.

Method can be called in following way's

  1. Call by Value

  2. Call by Refrence

  3. Call by Output

  4. Call by Params

Call by Value:

using System;

namespace Practice
{
    internal class Program
    {
        //Create method:-
        static void CallByValueMethod(int x)
        {
            x = 100;
            Console.WriteLine("InSide methof value of x is:-"+x); //100
        }
        static void Main(string[] args)
        {
            int a = 10;
            Console.WriteLine("value a before calling method: "+a);//10
            CallByValueMethod(a);//Call method with pass argument 
            //Not affact the `a` value in hear.
            Console.WriteLine("value a after calling method: "+a);//10
        }
    }
}
  • In Call by Value, any changes to the value of x inside the CallByValueMethod do not affect the value of a in the Main method.

Call by Refrence:

using System;

namespace Practice
{
    internal class Program
    {
        //Create method:-
        static void CallByValueRefrence(ref int x)
        {
            x = 100;
            Console.WriteLine("InSide methof value of x is:-"+x); //100
        }
        static void Main(string[] args)
        {
            int a = 10;
            Console.WriteLine("value a before calling method: "+a);//10
            CallByValueRefrence(ref a);
            //Affact the `a` value in hear.
            Console.WriteLine("value a after calling method: "+a);//100
        }
    }
}
  • When we use the ref keyword in an argument and parameter, it affects the original value. This is because ref passes a reference to the value, so any changes to x in CallByValueReference will affect the original value.

Call by Output:

  • By using out, you can effectively return multiple values from a method, leveraging both the method's return value and the out parameters.
using System;

namespace Practice
{
    internal class Program
    {
        // Create method:-
        static void CallByOutMethod(out int x)
        {
            x = 100; // Here, x is assigned the value 100
            Console.WriteLine("Inside method, value of x is: " + x); // 100
        }

        static int CallByOutMethod2(out int x)
        {
            x = 84; // Here, x is assigned the value 84
            Console.WriteLine("Inside method, value of x is: " + x); // 84
            return 28;
        }

        static void Main(string[] args)
        {
            int a = 10;
            Console.WriteLine("Value of a before calling method: " + a); // 10
            CallByOutMethod(out a); // Waiting for the method to assign a value to a
            Console.WriteLine("Value of a after calling method: " + a); // 100

            int n = CallByOutMethod2(out a);
            Console.WriteLine("Value of n is: " + n + " and a is: " + a); // n=28, a=84     
        }
    }
}
  • The out keyword is used to pass a reference to a variable and wait for the method to assign a value to it. If you want to use out, you must use the out keyword in both the argument and the parameter. Additionally, the out parameter must be assigned a value before the method returns.

Call by Params:

  • The params keyword lets a method take a variable number of arguments. You can pass a list of arguments to the method, and they will be treated as an array inside the method. This is helpful when you don't know in advance how many arguments you will pass.

Key Points:

  • Use ofparams: The params keyword is used in the method parameter to indicate that the method can accept a variable number of arguments.

  • Argument List: The arguments are passed as an array to the method.

  • Only Oneparams: A method can have only one params parameter, and it must be the last parameter in the method signature.

using System;

namespace Practice
{
    internal class Program
    {
        // Create method using `params` keyword
        static void PrintNumbers(params int[] numbers)
        {
            Console.WriteLine("Inside method, printing numbers:");
            foreach (int number in numbers)
            {
                Console.WriteLine(number);
            }
        }

        static void Main(string[] args)
        {
            // Calling the method with a variable number of arguments
            PrintNumbers(1, 2, 3, 4); // Output: 1, 2, 3, 4
            PrintNumbers(10, 20); // Output: 10, 20
            PrintNumbers(); // No output as no arguments were passed
        }
    }
}

In params parameter, when you pass the argument and you want to send diffrent type of

// 01: Example: Correct way to use
static void PrintNumbers(string s2, params int[] numbers)
{}
static void Main(string[] args)
{
    PrintNumbers("string",1, 2, 3, 4); 
}
// 02: Example: Correct way to use
static void PrintNumbers(int i, params int[] numbers)
{}
static void Main(string[] args)
{
    PrintNumbers(100, 1, 2, 3, 4); 
}

// 02: Example: Wrong way to use
static void PrintNumbers(params int[] numbers, string s2,)
{}
static void Main(string[] args)
{
    PrintNumbers(1, 2, 3, 4,"string"); 
}
// 03: Example: Wrong way to use
static void PrintNumbers(params int[] numbers, int i,)
{}
static void Main(string[] args)
{
    PrintNumbers(1, 2, 3, 4, 100); 
}
  • When we use the params keyword in a method parameter, it allows the method to accept a variable number of arguments. This means you can pass multiple arguments to the method, and they will be treated as an array inside the method. If you want to use params, it must be the last parameter in the method signature, and you can only have one params parameter per method.

Diffrence bitween out and ref parameter:

Example: ref

static void Main()
{
    int number = 10; // Must be initialized
    Console.WriteLine("Before calling ModifyRef: " + number); // Outputs 10
    ModifyRef(ref number);
    Console.WriteLine("After calling ModifyRef: " + number); // Outputs 20
}

static void ModifyRef(ref int x)
{
    x = x + 10; // Modifies the original value
}

Explanation:

  • The variable number is initialized to 10 before being passed to the ModifyRef method.

  • The ModifyRef method takes a ref parameter, meaning it can read and modify the original value.

  • Inside the method, x (which references number) is increased by 10, changing its value to 20.

  • After the method call, the original variable number reflects this change.

Example: out

static void Main()
{
    int number; // No need to initialize
    Console.WriteLine("Before calling AssignOut: uninitialized");
    AssignOut(out number);
    Console.WriteLine("After calling AssignOut: " + number); // Outputs 30
}

static void AssignOut(out int x)
{
    x = 30; // Must assign a value before returning
}

Explanation:

  • The variable number is declared but not initialized.

  • The AssignOut method takes an out parameter, meaning it must assign a value to x before returning.

  • Inside the method, x is assigned the value 30.

  • After the method call, the original variable number is now 30.

  • Initialization Before Call:

    • ref: The variable must be initialized before being passed to the method.

    • out: The variable does not need to be initialized before being passed to the method.

  • Reading Initial Value:

    • ref: The method can read the initial value of the parameter.

    • out: The method cannot read the initial value because it assumes the variable is uninitialized.

  • Assigning Value:

    • ref: The method can modify the existing value, but it doesn't have to assign a new value.

    • out: The method must assign a value to the parameter before returning.

Method working behind the screen:

  • When the method call it store in call stack.

  • I have one example understande it 1st:-

      using System;
    
      namespace Recursion
      {
          internal class Program
          {
              static void Main(string[] args)
              {
                  Console.WriteLine("1st: Main method run");
                  Method3(3);
              }
    
              static void Method3(int x)
              {
                  Console.WriteLine($"3nd: Method run and x = {x}");
                  Method2(2);
              }
              static void Method2(int x)
              {
                  Console.WriteLine($"2nd: Method run and x = {x}");
                  Method1(1);
              }
              //Method1 not call any methods
              static void Method1(int x)
              {
                  Console.WriteLine($"1nd: Method run and x = {x}");
              }
          }
      }
    
      //Output is:-
      //1st: Main method run
      //3nd: Method run and x = 3
      //2nd: Method run and x = 2
      //1nd: Method run and x = 1
    

Recursion

In previous last example,multiple method use same code then happen if the requiremr is 100 times, then we use recursion it mins function call itself.

using System;

namespace Recursion
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main method run");
            Method(3);
        }

        static void Method(int x)
        {
            Console.WriteLine($"x = {x}");
            Method(x-1);
        }
    }
}
//Output is:-
//1st: Main method run
//x = 3
//...
//...
//...
//Infnite time

In this example, the method calls itself infinitely, and each call is stored in the call stack. To stop the recursion, use a base condition to end the new calls. like that:

using System;

namespace Recursion
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main method run");
            Method(3);
        }

        static void Method(int x)
        {
            if (x == 0)
            {
                return;
            }
            Console.WriteLine($"x = {x}");
            Method(x-1);
        }
    }
}
//Output is:-
//1st: Main method run
//x = 3
//x = 2
//x = 1

If you are calling a function again and again, you can treat it as a sepret call in the stack. Also take seprate seprete memory. If you call the method infinitely, the stack/memory will fill up and it will give a stack overflow error.

Base condition:- If you don't use a base condition, the method will keep calling itself, and the stack will keep filling up. Since each method call uses memory, after some time the computer memory will exceed the limit..

example:

if (x == 0)return;

Why we need recursion:

  • It help us in solving bigger/complex problom in a simple way.

  • You can convert recursion solution into iteration & vice versa.

  • Space complecity is not constant because of recursive calls.

  • It help us to braking down bigger problom to smaller problom.

Recursion Tree:-

Let's understand by question:-

Q.1: Find the N th fibonacci number?

0, 1, 1, 2, 3, 5, 8, 13, ........

Poin 1: How you identify that question solved by recursion or not.

Point 2: Break down the question in to smoll question or pice like that:

fabonacci(n) = fabonacci(n-1) + fabonacci(n-2)

//code:
using System;
namespace Practical_Exercises
{
    internal class Program
    {
        static void Main()
        {
            Console.Write("Enter the number: ");
            int n = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine($"Fibonacci of {n} position is {Fabo(n)}");
            Console.ReadKey();
        }
        static int Fabo(int n)
        {
            if (n < 2) return n;
            return Fabo(n-1) + Fabo(n-2);
        }

    }
}

//Output:-
//Enter the number: 4
//Fibonacci of 4 position is 3

How does that work internally? Let's understand it:

  • One more thing: Fabo(n-1) and Fabo(n-2) are not the last lines in the Fabo() method. Also, Fabo(n-1) + Fabo(n-2) is not the last line. The last line in the Fabo() method is return Fabo(n-1) + Fabo(n-2);. In the Main() method, the last line is Console.ReadKey();. The idea of the last line being a function call is related to tail recursion, where the final action of a function is to call itself.

How to understande and approach an problome:

  • Identify if you can break down the problem into smaller problems.

  • Write the recurrence relation if needed.

  • Draw the recurrence tree.

  • About the tree:

    • See the flow of methods and how they are getting into the stack.

    • Identify and focus on the left tree call and the right tree call.

    • First, do the left method, then do the right method.

  • Draw the tree and positions again and again using pen and paper.

  • Use a debugger to see the flow.

  • See how the values are returned at each step, and see where the method call will come out. In the end, you will come out of the main method.

Very important things to focus on when solving recursion:

  1. Parameter.

  2. Return Type.

  3. Body of Code.

fabonacci(n) = fabonacci(n-1) + fabonacci(n-2) this is a recurence relation

Type of recurence relation:

  1. Linear Recurrence Relations with Constant Coefficients (ex: Fibonacci Sequence).

    • Recurrence Relation: F(n)=F(n−1)+F(n−2).

    • With initial conditions F(0)=0 and F(1)=1.

    • Explanation: Each term in the Fibonacci sequence is the sum of the two previous terms.

  2. Divide and Conquer Recurrence Relations (ex: Binary Search).

    • Recurrence Relation: T(n)=T(n/2)+O(1).

    • Explanation: Binary search splits the array in half each time, performing a constant amount of work in each step.

  3. Non-Homogeneous Recurrence Relations (ex**:** Factorial Calculation).

    • Recurrence Relation: T(n)=T(n−1)+O(n).

    • with T(0) = 1.Explanation: Calculating the factorial of a number (n) can be defined recursively by multiplying the result of ((n-1)!) by (n), plus the extra step for the multiplication operation.

In that example, when you enter 50 to find the 50th Fibonacci number, the program gets stuck.

static void Main()
{
  int n = 50
  CW(Fabo(n));
}
static int Fabo(int n)
{
  if (n < 2) return n;
  return Fabo(n-1) + Fabo(n-2);
}

Can you see that :-

This code repeats itself. Imagine how many times it will repeat if you input 50. That why program getting stuck.

Passing an array to a method & Return an array from a method:

Passing an Array to a Method:

When you pass an array to a method, you provide the method with the array reference. The method can then access and modify the elements of the array.

syntex:-ReturnType MethodName(DataType[] arrayParameter) { // Method body }

Example:-

using System;

class Program
{
    // Method that takes an array as a parameter and prints its elements
    static void PrintArray(int[] array)
    {
        foreach (int item in array)
        {
            Console.WriteLine(item);
        }
    }

    static void Main()
    {
        int[] numbers = { 1, 2, 3, 4, 5 };
        PrintArray(numbers);
    }
}

Returning an Array from a Method:

You can also return an array from a method. The return type of the method should be the array type.

Syntex:-DataType[] MethodName() { // Method body that creates and returns an array } .

Example:-

using System;

class Program
{
    // Method that returns an array of integers
    static int[] GenerateArray(int size)
    {
        int[] array = new int[size];
        for (int i = 0; i < size; i++)
        {
            array[i] = i * 2; // Just an example of initialization
        }
        return array;
    }

    static void Main()
    {
        int[] generatedArray = GenerateArray(5);

        // Print the returned array
        foreach (int item in generatedArray)
        {
            Console.WriteLine(item);
        }
    }
}

Combining Both: Passing an Array and Returning an Array:

using System;
class Program
{
    // Method that takes an array, modifies it, and returns a new array
    static int[] ModifyArray(int[] array)
    {
        return array;
    }
    static void Main()
    {
        int[] originalArray = { 1, 2, 3, 4, 5 };
        int[] newArray = ModifyArray(originalArray);
    }
}

Params:

It is used to pass variable no. of arguments to a method.

In C#, params is a keyword used in method parameters to specify that the method can accept a variable number of arguments of a particular type. It allows you to pass a variable number of parameters to a method as an array.

Stntex:ReturnType MethodName(params DataType[] parameterName) { // Method body } .

params: It indicates that the parameter array can accept zero or more arguments of the specified type.

DataType[] parameterName: This is the parameter array declaration. It can accept multiple arguments of type DataType.

using System;

class Program
{
    // Method that calculates the sum of integers using params
    static int Sum(params int[] numbers)
    {
        int sum = 0;
        foreach (int num in numbers)
        {
            sum += num;
        }
        return sum;
    }

    static void Main()
    {
        // Calling the Sum method with different number of arguments
        int result1 = Sum(1, 2, 3);          // Passing 3 arguments
        int result2 = Sum(4, 5);             // Passing 2 arguments
        int result3 = Sum(6, 7, 8, 9, 10);   // Passing 5 arguments

        Console.WriteLine("Result 1: " + result1);   // Output: 6
        Console.WriteLine("Result 2: " + result2);   // Output: 9
        Console.WriteLine("Result 3: " + result3);   // Output: 40
    }
}

Key Points

  • You can use params only for the last parameter in a method's parameter list.

  • The params keyword must be followed by an array type.

  • When calling a method with params, you can pass arguments directly without explicitly creating an array.

Benefits of Using params

  1. Flexibility: It allows methods to accept a variable number of arguments, making them more flexible.

  2. Convenience: You can pass arguments directly without creating an array explicitly.

  3. Simplifies Method Overloading: Reduces the need for multiple method overloads for different parameter counts.

Limitations

  • The params parameter must be the last parameter in the method's parameter list.

  • You can have only one params parameter in a method signature.

When to Use params

  • Use params when you have methods that need to accept a variable number of arguments of the same type, such as in utility methods or mathematical operations where the number of operands can vary.

params in C# provides a convenient way to work with methods that accept a variable number of arguments, simplifying the code and enhancing flexibility.

Exceptions and Exception Handling

Generally, when we develop the application, we get two different types of errors:

  1. Compile-time error (Syntactical error called compile-time error).

  2. Run-time error (The errors that occur during execution are called run-time errors).

Compile-time error:

Syntactical errors, also known as compile-time errors, are not dangerous and can be fixed during development. These errors occur when you run the program at the developing stage.

Run-time error:

Run-time errors happen when the program is running. They can be caused by wrong inputs, incorrect logic, database network problom missing necessary resources & etc. Example: Assume you have an array with a size of 5 and using a for loop you try to add a 6th value. At that time come error occur.These are dangerous because if a run-time error occurs, the program gets abnormally terminated without executing the next line of code. For example, assume you have 1000 lines of code. If an error occurs on the 100th line, the program will abnormally terminate, and the remaining 900 lines will not execute. Compile cannot check the logic, it only checks syntax because everyone implements different logic.

Who is responsible for abnormally terminated:

The exception is responsible for the program's abnormal termination. An exception is a class.

Whenever any error occurs in the program, the exception class is triggered, and it abnormally terminates the program.

An exception is not a run-time error itself. When run-time errors happen in the code, an exception occurs and causes of exception the program abnormally terminates. An exception is a class, and there are different classes for each type of run-time error. Example: IndexOutOfBoundsException is a run-time error and the name of a class. This error occurs when you try to add more values than the size of the array. Because of the IndexOutOfBoundsException class, your program abnormally terminates. For program abnormally terminates lot's of predefine class are available like DivideByZeroException, OverflowException, FormatException and etc. And all this class present in Exception class.

How predefined exception classes are implemented in our library:

A class named Exception is available with logic for abnormal termination. This class contains a readonly property to display an error message, which is declared as virtual (meaning child classes can overwrite it) and the property name is "Message.

Under this Exception, two child classes are defined:

  • Application Exception: This is a base class for exceptions that are specifically defined by your application. You can create custom exception classes derived from ApplicationException to handle specific errors unique to your program.

  • System Exception: This is a base class for exceptions that are thrown by the .NET runtime system. It includes common errors like memory access violations or arithmetic overflows. Examples include NullReferenceException and IndexOutOfRangeException.

In short, ApplicationException is for custom errors in your code, while SystemException is for general errors handled by the .NET system.

All the predefined exception come under the SystemException Like :

  1. IndexOutOfBoundsException

  2. Formet Exception

    • DivideByZeroException

    • OverflowException

Why this many error are available?

To clarify which type of error occurs in the program. Different types of errors occur in different scenarios. This all predefine class's.

using System;

class ExceptionHandle
{
    static void Main()
    {
        Console.WriteLine(10/0);
    }
}

Come error:- ExceptionHandle.cs(7,21): error CS0020: Division by constant zero

How the exception will arise: All the .NET applications running are monitored by the CLR. The CLR is going to monitor the application, and it is the execution engine responsible for running the program. All programs run under the supervision of the CLR. When execution is ongoing, the CLR identifies the mistake in the line, then the CLR stops the program and checks the mistake. After that, the CLR will pick the class associated with this mistake (like Division by constant zero). Now the CLR creates an instance of that class and throws the object. The object thrown by the CLR causes the program is terminate abnormally. Once the program terminates abnormally, it shows the message and does not execute the next line after the error line.

To handle the program terminate abnormally we use Exception handling.

Exception handling:

Exception handling is used to stop the abnormal termination of a program whenever a runtime error occurs in the program.

We can show user-friendly error messages to the end users to explain the error.

We can take corrective actions to fix problems that may happen because of the error like when money is transferred from one account to another, if there are two processes: first, deducting the money from one account, and second, adding the money to another account. But assume the first task completes, and when adding money to the other account an error occurs. This is where exception handling comes in. If any error occurs in the second task, then the first task is canceled.

To handle an exception, we use two special blocks: the first is try, and the second is catch.

using System;

class ExceptionHandle
{
    static void Main()
    {
        try
        {
            //Statement's which will cause runtime error
            //Statement's which doesn't require exception when the runtime error occured  
        }
        catch(<Exception Class Name> <Variable>)
        {
            //Statement's which should execute only when there is a runtime error
        }    
    }
}

Example:

using System;

class ExceptionHandle
{
    static void Main()
    {
        Console.WriteLine("Hello World");
        try
        {
            Console.WriteLine("We are try to run the exception code!");
            Console.Write("Enter the \'a\' value: ");
            int a = Convert.ToInt32(Console.ReadLine());
            Console.Write("Enter the \'b' value: ");
            int b= Convert.ToInt32(Console.ReadLine());
            int x = a/b;    
            Console.WriteLine("Your Answer is :" + x);
        }
        catch(DivideByZeroException ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
/*Output is:- 
Hello World
We are try to run the exception code!
Enter the 'a' value: 12
Enter the 'b' value: 0
Attempted to divide by zero.
*/

Here, the CLR creates an instance of the DivideByZeroException class and throws it. This instance is thrown by the CLR to perform the abnormal termination. However, because we use try-catch block, here, before performing the abnormal termination, the catch block catches the instance. Once the instance is caught by the catch block, the abnormal termination stops. Then the instance is stored in ex. What is ex? ex is the variable of the class.

Remember, the instance of the class is assigned to the ex variable of the class. Once the assignment is done, the variable (ex) is a reference to the DivideByZeroException class. Then the catch block performs the task.

Sometimes, this error also occurs in this code. The name of the error is FormatException:

Hello World
We are try to run the exception code!
Enter the 'a' value
43
Enter the 'b' value
Mo

Unhandled Exception: System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at ExceptionHandle.Main()

To solve that, we use another catch block:

using System;

class ExceptionHandle
{
    static void Main()
    {
        Console.WriteLine("Hello World");
        try
        {
            Console.WriteLine("We are try to run the exception code!");
            Console.Write("Enter the \'a\' value: ");
            int a = Convert.ToInt32(Console.ReadLine());
            Console.Write("Enter the \'b' value: ");
            int b= Convert.ToInt32(Console.ReadLine());
            int x = a/b;
            Console.WriteLine("Your Answer is :" + x);
        }
        catch(DivideByZeroException ex)
        {
            Console.WriteLine(ex.Message);
        }
        catch(FormatException ex1)
        {
            Console.WriteLine(ex1.Message);
        }
    }
}
/*Output is:
Hello World
We are try to run the exception code!
Enter the 'a' value: 3
Enter the 'b' value: f
Input string was not in a correct format.
*/

Assume you know only two errors can happen, and you handle them. But what if an unknown error occurs when the application is developed? To fix this, we use a parent class called Exception in last catch block like that.

using System;

class ExceptionHandle
{
    static void Main()
    {
        Console.WriteLine("Hello World");
        try
        {
            Console.WriteLine("We are try to run the exception code!");
            Console.Write("Enter the \'a\' value: ");
            int a = Convert.ToInt32(Console.ReadLine());
            Console.Write("Enter the \'b' value: ");
            int b= Convert.ToInt32(Console.ReadLine());
            int x = a/b;
            Console.WriteLine("Your Answer is :" + x);
        }
        catch(DivideByZeroException ex)
        {
            Console.WriteLine(ex.Message);
        }
        catch(FormatException ex1)
        {
            //Custome Error show:
            Console.WriteLine("We cannot take another datatype value");
        }
        catch(Exception ex2)
        {
            Console.WriteLine(ex2.Message);
        }
    }
}
/*Output:-
Hello World
We are try to run the exception code!
Enter the 'a' value: 3
Enter the 'b' value: 4444444444444444444444444444444
3rd catch run: Value was either too large or too small for an Int32.
*/

Apart from these two exceptions, DivideByZeroException and FormatException, any other exception will go to the Exception class. Specialty of this Exception class is it catches any exception that is not handled by any of the other catch blocks like else block in if-else or default block in switch-case.

If the Exceptionclass is available, then why do we useDivideByZeroExceptionandFormatExceptionclasses:

Because of 2 reasons: The 1st is to perform different approaches in different scenarios. It means knowing what action to take after encountering an error. I take one action if a DivideByZeroException error occurs and another action if a FormatException error occurs. The 2nd is if you use only the Exception class and not any particular class, it takes a lot of time for the compiler to find the specific class and takes more time.

That way, we use the Exception class last. If any error happens that does not match with the previously defined exceptions or catches, then only the last catch, which is the Exception class, will handle it.

One more thing, if an exception does not occur, then none of the catch blocks will execute. If any exception occurs in the try block, it jumps to the catch block and searches for the catch block that handles this exception. If there is a match, abnormal termination does not happen, and it runs all statements that are present after the catch block. If the exception does not match any catch block, abnormal termination occurs.

using System;
class ExceptionHandle
{
    static void Main()
    {
        try
        {
            Console.Write("Enter the \'a\' value: ");
            int a = Convert.ToInt32(Console.ReadLine());
            Console.Write("Enter the \'b' value: ");
            int b= Convert.ToInt32(Console.ReadLine());
            int x = a/b;
            Console.WriteLine("Your Answer is :" + x);
            Console.WriteLine("I am run after the error come and i am also inside the try block");
        }
        catch(DivideByZeroException ex)
        {
            Console.WriteLine(ex.Message);
        }
        Console.WriteLine("I am run after the error come and i am also outside the try block");
    }
}
/*Output:-
Enter the 'a' value: 2
Enter the 'b' value: 0
Attempted to divide by zero.
I am run after the error come and i am also outside the try block
*/

One more block is there named finally, Syntex:

try
{
//Statement's which will cause runtime error
//Statement's which doesn't require exception when the runtime error occured  
}
catch(<Exception Class Name> <Variable>)
{
//Statement's which should execute only when there is a runtime error
}    
finally
{
//Statement's run alwase if Exception come or not
}

This finally block always runs whether an exception occurs or not. Why do we need it? Assume you open a file to do some task, but an exception occurs, or you complete the work correctly. The finally block is used to close the file whether an exception happens or you complete the task both the case.

try
{
//Open a file
//Write into the file 
/*If you close the file hear but if any error come in 
writing into the file then close the file  code not work. 
That why we write the close file code in finaly block*/ 
}
catch(<Exception Class Name> <Variable>)
{
//if error come then run
}    
finally
{
//close the file
}

If you close the file in the try block, but an error occurs while writing into the file, the code to close the file will not work. That is why we write the code to close the file in the finally block.

Finally block is mandatory for execution.

One thing you might be confused about is the purpose of using the finally block. We can also close the file after the catch block without using the finally block. Here is an example to clear the doubt:

using System;

class ExceptionHandle
{
    static void Main()
    {
        try
        {
            Console.Write("Enter the \'a\' value: ");
            int a = Convert.ToInt32(Console.ReadLine());
            Console.Write("Enter the \'b' value: ");
            int b= Convert.ToInt32(Console.ReadLine());
            if(b == 1)
            {
                return;
            }
            int x = a/b;
            Console.WriteLine("Your Answer is :" + x);

        }
        catch(DivideByZeroException ex)
        {
            Console.WriteLine(ex.Message);
        }
        catch(Exception ex2)
        {
            Console.WriteLine("3rd catch run: "+ex2.Message);
        }
        finally
        {
            Console.WriteLine("Finaly block execute");
        }
    }
}
/*Output:-
Enter the 'a' value: 2
Enter the 'b' value: 1
Finaly block execute
*/

Hear what happens when we use return; in the if block. According to the return keyword, return is used to exit the method. It means when we use return inside the method, the method execution finishes and control goes outside the method. But here, in the try-catch-finally block, when we use return;, it doesn't go anywhere because the finally block runs in any how condition. It's mandatory.

some points:

  1. Exception is caught by the catch block because the exception caught by the catch block does not cause abnormal termination.

  2. Finally block runs in any condition, it's mandatory.

  3. Without writing a catch block, if we use only the try-finally block, then the exception is not caught, causing abnormal termination happend, but the finally block will alwase execute.

     using System;
    
     class ExceptionHandle
     {
         static void Main()
         {
             try
             {
                 Console.Write("Enter the \'a\' value: ");
                 int a = Convert.ToInt32(Console.ReadLine());
                 Console.Write("Enter the \'b' value: ");
                 int b= Convert.ToInt32(Console.ReadLine());
                 int x = a/b;
                 Console.WriteLine("Your Answer is :" + x);
    
             }
             finally
             {
                 Console.WriteLine("Finaly block execute");
             }
         }
     }
     /* Output:-
     Enter the 'a' value: 2
     Enter the 'b' value: 0
    
     Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
        at ExceptionHandle.Main()
     Finaly block execute
     */
    

Application Exception:

In System Exception, when any error occurs, such as division by zero or any incorrect condition like dividing any number by zero, the CLR tracks this and throws an instance, causing abnormal termination.

In an Application Exception, the CLR does not throw the instance for abnormal termination. The programmer or application developer creates the class and throws the instance.

To create the instance of a class to throw the instance of a class:

ApplicationException ex = new ApplicationException("<Error message>");

throw ex; // throw the ex

Or

throw new ApplicationException("<Error message>");

Exactly CLR doing like same thing's.

Explain: ApplicationException ex = new ApplicationException("<Error message>");

  • On the left side of the = sign, ApplicationException is the class name and ex is the instance of the class or instance name.

  • On the right side of the = sign, ApplicationException is a constructor of the ApplicationException class, and new is used to allocate memory.

  • ("<Error message>") is a parameter to pass the error message.

Don't think too much about class and constructor; we will learn about them later.

Explain: throw new ApplicationException("<Error message>");

  • Instance is created and thrown without needing to create the instance name. We require an instance name when calling any member, but if not calling any member, there is no need to create an instance name. So, throw new ApplicationException("<Error message>"); this is an instance but unnamed.

Example: I make an exception when the divider value is an odd number, then the exception occurs.

try
{
    Console.Write("Enter the \'a\' value: ");
    int a = Convert.ToInt32(Console.ReadLine());
    Console.Write("Enter the \'b' value: ");
    int b= Convert.ToInt32(Console.ReadLine());
    if(b%2 > 0)
    {
    throw new ApplicationException("b vale is odd number!");
    }
    int x = a/b;
    Console.WriteLine("Your Answer is :" + x);    
}
catch(Exception ex2)
{
    Console.WriteLine(ex2.Message);
}
finally
{
    Console.WriteLine("Finaly block execute");
}
/*Output:-
Enter the 'a' value: 2
Enter the 'b' value: 3
b vale is odd number!
Finaly block execute
*/
try
{
    Console.Write("Enter the \'a\' value: ");
    int a = Convert.ToInt32(Console.ReadLine());
    Console.Write("Enter the \'b' value: ");
    int b= Convert.ToInt32(Console.ReadLine());
    if(b%2 > 0)
    {
    throw new ApplicationException("b vale is odd number!");
    }
    int x = a/b;
    Console.WriteLine("Your Answer is :" + x);    
}
catch(ApplicationException ex2)
{
    Console.WriteLine(ex2.Message);
}
finally
{
    Console.WriteLine("Finaly block execute");
}
/*Output:-
Enter the 'a' value: 2
Enter the 'b' value: 3

Unhandled Exception: System.ApplicationException: b vale is odd number!
   at ExceptionHandle.Main()
Finaly block execute
*/
try
{
    Console.Write("Enter the \'a\' value: ");
    int a = Convert.ToInt32(Console.ReadLine());
    Console.Write("Enter the \'b' value: ");
    int b= Convert.ToInt32(Console.ReadLine());
    if(b%2 > 0)
    {
    throw new ApplicationException("b vale is odd number!");
    }
    int x = a/b;
    Console.WriteLine("Your Answer is :" + x);    
}
catch(ApplicationException ex2)
{
    Console.WriteLine(ex2.Message);
}
finally
{
    Console.WriteLine("Finaly block execute");
}
/*Output:-
Enter the 'a' value: 2
Enter the 'b' value: 3
b vale is odd number!
Finaly block execute
*/

Remember Points:

  • If you do not pass the message likethrow new ApplicationException();, then the error will beError in the application.

  • If you do not handle the programmer-defined exception, an error will occur.

ApplicationException is a class provided by the .NET Framework that serves as a base class for application-defined exceptions. It allows you to create custom exceptions that can be used to handle specific error conditions in your application.

In that error Unhandled Exception: System.ApplicationException: b vale is odd number! at ExceptionHandle.Main(), I want to replace System.ApplicationException with System.DivideByOddNumberException. How do I do that?

To do that, we need our own class. To define our own Exception class:

Example:

using System;

public class DivideByOddNumberException: ApplicationException
{
  public override string Message
  {
  get
    {
      return "Attempted to divide by odd number.";
    }
  }
}//End DivideByOddNumberException class

class ExceptionHandle
{
  static void Main()
  {
    try
    {
      Console.Write("Enter the \'a\' value: ");
      int a = Convert.ToInt32(Console.ReadLine());
      Console.Write("Enter the \'b' value: ");
      int b= Convert.ToInt32(Console.ReadLine());
      if(b%2 > 0)
        {
          throw new DivideByOddNumberException();
        }
      int x = a/b;
      Console.WriteLine("Your Answer is :" + x);    
    }
    catch(DivideByOddNumberException ed)
    {
      Console.WriteLine(ed.Message);
    }
    finally
    {
      Console.WriteLine("Finaly block execute");
    }
  }
}
/*Output:- 
Enter the 'a' value: 5
Enter the 'b' value: 3
Attempted to divide by odd number.
Finaly block execute
*/

A file can contain multiple classes, but remember only one class can have the Main() method.

Here, DivideByOddNumberException inherits from ApplicationException, and ApplicationException inherits from the Exception class. In the Exception class, there is a virtual read-only property named Message. You can override this property. By default, the message in the Message property is Error in the application, but I need my own message.

Not work when you do not throw the programmer-created exception like here DivideByOddNumberException is a programmer-created exception.

using System;

public class DivideByOddNumberException: ApplicationException
{
  public override string Message
  {
  get
    {
      return "Attempted to divide by odd number.";
    }
  }
}

class ExceptionHandle
{
  static void Main()
  {
    try
    {
      Console.Write("Enter the \'a\' value: ");
      int a = Convert.ToInt32(Console.ReadLine());
      Console.Write("Enter the \'b' value: ");
      int b= Convert.ToInt32(Console.ReadLine());
      int x = a/b;
      Console.WriteLine("Your Answer is :" + x);    
    }
    catch(DivideByOddNumberException ed)
    {
      Console.WriteLine(ed.Message);
    }
    catch(Exception e)
    {
      Console.WriteLine(e.Message);
    }
    finally
    {
      Console.WriteLine("Finaly block execute");
    }
  }
}
/*Output is:-
Enter the 'a' value: 9
Enter the 'b' value: 3
Your Answer is :3
Finaly block execute
*/

You see, here DivideByOddNumberException does not work because we did not throw it in the try block.

using System;

public class DivideByOddNumberException: ApplicationException
{
  public override string Message
  {
  get
    {
      return "Attempted to divide by odd number.";
    }
  }
}//End DivideByOddNumberException class

class ExceptionHandle
{
  static void Main()
  {
    try
    {
      Console.Write("Enter the \'a\' value: ");
      int a = Convert.ToInt32(Console.ReadLine());
      Console.Write("Enter the \'b' value: ");
      int b= Convert.ToInt32(Console.ReadLine());
      if(b%2 > 0)
        {
          throw new DivideByOddNumberException();
        }
      int x = a/b;
      Console.WriteLine("Your Answer is :" + x);    
    }
    finally
    {
      Console.WriteLine("Finaly block execute");
    }
  }
}
/*Output:- 
Enter the 'a' value: 9
Enter the 'b' value: 3

Unhandled Exception: DivideByOddNumberException: Attempted to divide by odd number.
   at ExceptionHandle.Main()
Finaly block execute
*/

Here you see both error messages Unhandled Exception: DivideByOddNumberException: and Unhandled Exception: System.ApplicationException: in System are present in the ApplicationException error message, but nothing is there in the DivideByOddNumberException error message. To fix that, use the namespace like this:

using System;
namespace MyNsp
{
public class DivideByOddNumberException: ApplicationException
{
  public override string Message
  {
  get
    {
      return "Attempted to divide by odd number.";
    }
  }
}//End DivideByOddNumberException class

class ExceptionHandle
{
  static void Main()
  {
    try
    {
      Console.Write("Enter the \'a\' value: ");
      int a = Convert.ToInt32(Console.ReadLine());
      Console.Write("Enter the \'b' value: ");
      int b= Convert.ToInt32(Console.ReadLine());
      if(b%2 > 0)
        {
          throw new MyNsp.DivideByOddNumberException();
        }
      int x = a/b;
      Console.WriteLine("Your Answer is :" + x);    
    }
    finally
    {
      Console.WriteLine("Finaly block execute");
    }
  }
}
}

/*Output:- 
Enter the 'a' value: 9
Enter the 'b' value: 3

Unhandled Exception: MyNsp.DivideByOddNumberException: Attempted to divide by odd number.
   at MyNsp.ExceptionHandle.Main()
Finaly block execute
*/

File System: Managing Folders and Files

Stream is a flow of data from one direction to another. There are two types of Streams:

  1. Input Stream

  2. Output Stream

Input Stream is used to read from the user, whereas Output Stream is used to display data on the console.

File Stream is used to work with files, meaning writing data into files or reading data from files.

To work with File Streams in C#, we have to use the namespace called System.IO. The following classes are used to work with FileStreams in C#:

  1. FileStream

  2. StreamWriter

  3. StreamReader

  4. BinaryWriter

  5. BinaryReader

  6. FileInfo

  7. DirectoryInfo

FileStream : It is a class which is used to open a file by specifying the name,path, mode and access.

Modes:

Create: to create a new file. If the file is already exists then it will overwritten.

CreateNew: to create a new file. If the file is already exists then it will raise an Exception.

Open: to open an existing file.

OpenOrCreate: If the file exists it will open otherwise it will create a new file.

Append: to add data to an existing file.

Truncate: to delete the contents of the file

Access:

Write: to create a new file and to write data into it.

Read: to read data from an existing file.

ReadWrite: used for both reading and writing.

Get all folders inside any folder:

using System;
using System.IO;

namespace FileStream
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string rootPath = @"D:\dotnet\Practice\FileStream";
            //Get all folder in side the FileStream folder
            string[] dirs = Directory.GetDirectories(rootPath);
            foreach (string dir in dirs)
            {
                Console.WriteLine(dir);
            }
        }
    }
}
/*Out:-
D:\dotnet\Practice\FileStream\All_example_file
D:\dotnet\Practice\FileStream\bin
D:\dotnet\Practice\FileStream\obj
D:\dotnet\Practice\FileStream\Properties
*/

Why do we use @"D:\dotnet\Practice\FileStream"? Because the @ symbol before a string literal creates a verbatim string.

What is verbatim string? Verbatim strings ignore escape sequences like \ and treat the backslash as a normal character. This is especially useful for file paths and regular expressions, where backslashes are often used.

Example without Verbatim String: "D:\dotnet\Practice\FileStream";

Example with Verbatim String: @"D:\dotnet\Practice\FileStream";

We get the same result using either without a Verbatim String or with a Verbatim String.

Directory.GetDirectories() returns a string array.

Access the File and Folder/Directory:

Get all folders inside any folder/Directory with sub folder:

using System;
using System.IO;

internal class Program
{
    static void Main(string[] args)
    {
        string rootPath = "D:\\dotnet\\Practice\\FileStream";
        //Get all folder in side the FileStream folder
        string[] dirs = Directory.GetDirectories(rootPath,"*",SearchOption.AllDirectories);  
        foreach (string dir in dirs)
        {
            Console.WriteLine(dir);
        }
    }
}

/*Out:-
D:\dotnet\Practice\FileStream\All_example_file
D:\dotnet\Practice\FileStream\bin
D:\dotnet\Practice\FileStream\obj
D:\dotnet\Practice\FileStream\Properties
D:\dotnet\Practice\FileStream\bin\Debug
D:\dotnet\Practice\FileStream\obj\Debug
D:\dotnet\Practice\FileStream\obj\Debug\TempPE
*/

Get all files inside any folder:

using System;
using System.IO;
internal class Program
{
    static void Main(string[] args)
    {
        string rootPath = "D:\\dotnet\\Practice\\FileStream";

        //Get all folder in side the FileStream folder
        string[] dirs = Directory.GetFiles(rootPath,"*.*",SearchOption.TopDirectoryOnly);
        foreach (string dir in dirs)
        {
            Console.WriteLine(dir);
        }
    }
}
/*Out:-
D:\dotnet\Practice\FileStream\App.config
D:\dotnet\Practice\FileStream\FileStream.csproj
D:\dotnet\Practice\FileStream\Program.cs
*/

Get all files inside any folder with subfolder files:

string[] dirs = Directory.GetFiles(rootPath,"*.*",SearchOption.AllDirectories);
/*Out:-
D:\dotnet\Practice\FileStream\App.config
D:\dotnet\Practice\FileStream\FileStream.csproj
D:\dotnet\Practice\FileStream\Program.cs
D:\dotnet\Practice\FileStream\bin\Debug\FileStream.exe
D:\dotnet\Practice\FileStream\bin\Debug\FileStream.exe.config
D:\dotnet\Practice\FileStream\bin\Debug\FileStream.pdb
D:\dotnet\Practice\FileStream\obj\Debug\.NETFramework,Version=v4.7.2.AssemblyAttributes.cs
D:\dotnet\Practice\FileStream\obj\Debug\DesignTimeResolveAssemblyReferencesInput.cache
D:\dotnet\Practice\FileStream\obj\Debug\FileStream.csproj.AssemblyReference.cache
D:\dotnet\Practice\FileStream\obj\Debug\FileStream.csproj.CoreCompileInputs.cache
D:\dotnet\Practice\FileStream\obj\Debug\FileStream.csproj.FileListAbsolute.txt
D:\dotnet\Practice\FileStream\obj\Debug\FileStream.exe
D:\dotnet\Practice\FileStream\obj\Debug\FileStream.pdb
D:\dotnet\Practice\FileStream\Properties\AssemblyInfo.cs
*/

Get all files inside any folder with subfolder/SubDirectory files without path:

string rootPath = @"D:\dotnet\Practice\FileStream";
//Get all folder in side the FileStream folder
string[] dirs = Directory.GetFiles(rootPath,"*.*",SearchOption.AllDirectories);
foreach (string dir in dirs)
{
    Console.WriteLine(Path.GetFileName(dir));
}
/*Out:-
App.config
FileStream.csproj
Program.cs
FileStream.exe
FileStream.exe.config
FileStream.pdb
.NETFramework,Version=v4.7.2.AssemblyAttributes.cs
DesignTimeResolveAssemblyReferencesInput.cache
FileStream.csproj.AssemblyReference.cache
FileStream.csproj.CoreCompileInputs.cache
FileStream.csproj.FileListAbsolute.txt
FileStream.exe
FileStream.pdb
AssemblyInfo.cs
*/

More example:-

string rootPath = @"D:\dotnet\Practice\FileStream";

//Get all folder in side the FileStream folder
string[] dirs = Directory.GetFiles(rootPath,"*.*",SearchOption.AllDirectories);
foreach (string dir in dirs)
{
    Console.WriteLine(Path.GetFileNameWithoutExtension(dir));//If you want to get the file name without the extension
    Console.WriteLine(Path.GetFullPath(dir));//If you want to get the full path
    Console.WriteLine(Path.GetDirectoryName(dir));//Get directry name

    //Get file information:-
    var info = new FileInfo(dir);
    Console.WriteLine(info.Length);
    Console.WriteLine($"{info.Length} bytes");

    //ETC:-
}

Cheak folder/Directory exists or not:

string rootPath = @"D:\dotnet\Practice\FileStream";

//Cheak Folder exist or not
bool directoryExists = Directory.Exists(rootPath + "\\SubFolder");
Console.WriteLine(directoryExists);//Out: False

bool directoryExists2 = Directory.Exists(rootPath + "\\All_example_file");
Console.WriteLine(directoryExists2);//Out: True

Create Folder/Directory:

string rootPath = @"D:\dotnet\Practice\FileStream";

//Cheak Folder exist or not
bool directoryExists = Directory.Exists(rootPath + "\\SubFolder");
Console.WriteLine(directoryExists);//Out: False
if (!directoryExists) 
{
    Directory.CreateDirectory(rootPath + "\\SubFolder");
}

directoryExists = Directory.Exists(rootPath + "\\SubFolder");
Console.WriteLine(directoryExists);//Out: True

Copy the files and paste another folder:

string rootPath = @"D:\dotnet\Practice\FileStream";
string destany = @"D:\dotnet\Practice\FileStream\All_example_file\";

//copy-pest
string[] files = Directory.GetFiles(rootPath);
foreach (string file in files)
{
    File.Copy(file, $"{destany}{Path.GetFileName(file)}", true);
    //true use to not overwrite, false is to overwrite
}

Move files:

string rootPath = @"D:\dotnet\Practice\FileStream\All_example_file";
string destany = @"D:\dotnet\Practice\FileStream\SubFolder\";

string[] files = Directory.GetFiles(rootPath);
foreach (string file in files)
{
    File.Move(file, $"{destany}{Path.GetFileName(file)}");
}

Get particullar extension named files:

string rootPath = @"D:\dotnet\Practice\FileStream\All_example_file";
var files = Directory.GetFiles(rootPath,"*.txt*",SearchOption.AllDirectories);
foreach (string file in files)
{
    Console.WriteLine(file);
}

Search files using name:

string rootPath = @"D:\dotnet\Practice\FileStream\SubFolder";
var files = Directory.GetFiles(rootPath, "*testDemo*.*", SearchOption.AllDirectories);
foreach (string file in files)
{
    Console.WriteLine(file);
}

Programs using FileStreams

  1. Writing data into a new file

  2. Appending data to an existing file

  3. Reading data from an existing file

  4. Deleting a file

Writing & Appending data into a new file:

string filePath = @"D:\dotnet\Practice\FileStream\All_example_file\testDemo.txt";
FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
//or Appending
//FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write);
StreamWriter writer = new StreamWriter(fs);

writer.Write("Hello World");
writer.Flush();
writer.Close();//CLose the file
fs.Close();//Close the FileStream

Reading data from an existing file:

string filePath = @"D:\dotnet\Practice\FileStream\All_example_file\testDemo.txt";
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
StreamReader writer = new StreamReader(fs);

string data  = writer.ReadLine();
Console.WriteLine(data);
writer.Close();
fs.Close();

Deleting a file:

 string filePath = @"D:\dotnet\Practice\FileStream\All_example_file\testDemo.txt";
 // Cheak file exist or not
 if (File.Exists(filePath))
 {
     File.Delete(filePath); // Deleting the file
 }

Deleting a folder:

string Path = @"D:\dotnet\Practice\FileStream\SubFolder";
// Cheak folder exist or not
if (Directory.Exists(Path))
{
   //Delete folder
   Directory.Delete(Path, true);// true for recursive deletion 
}

Accept n value from user and ask for n students details and store it:

string filePath = @"D:\dotnet\Practice\FileStream\All_example_file\demo.txt";

FileStream fs = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write);
StreamWriter writer = new StreamWriter(fs);
for (int i = 0; i < 3; i++)
{
    Console.Write("Enter id: ");
    int id = Convert.ToInt32(Console.ReadLine());
    Console.Write("Enter Name: ");
    string name = Console.ReadLine();

    //writer.Write($"id: {id}, name: {name}");
    //or
    writer.WriteLine($"id: {id}, name: {name}");
}
writer.Flush();
writer.Close();
fs.Close();

Read all students details from the file and display.

string filePath = @"D:\dotnet\Practice\FileStream\All_example_file\demo.txt";

FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
StreamReader writer = new StreamReader(fs);

//string data = writer.ReadLine();//Read only first line
string data = writer.ReadToEnd();//Read only first line
Console.WriteLine(data);

writer.Close();
fs.Close();

Writing Binary data into file and reading data from Binary file.

string filePath = @"D:\dotnet\Practice\FileStream\All_example_file\demo.txt";

//Write:-
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Write);
BinaryWriter writer = new BinaryWriter(fs);

int a = 47;
string b = "Mritunjay";
double c = 12.45;

writer.Write(a);
writer.Write(b);
writer.Write(c);

writer.Flush();
writer.Close();
fs.Close();

//Read:- 
FileStream fsr = new FileStream(filePath, FileMode.Open, FileAccess.Read);
BinaryReader read = new BinaryReader(fsr);

Console.WriteLine(read.ReadInt32());//Out:- 47
Console.WriteLine(read.ReadString());//Out:- Mritunjay
Console.WriteLine(read.ReadDouble());//Out:- 12.45

read.Close();
fsr.Close();

You've successfully completed the basics of C# programming!. These fundamentals are crucial for building more complex and efficient applications.

Next Steps:

To advance your C# skills, consider exploring these topics:

  • Object-Oriented Programming (OOP)

  • LINQ (Language Integrated Query)

  • Asynchronous Programming

  • Advanced Data Structures

  • Design Patterns

Check out the Learn C#.NET Advancec Level tutorials and resources on advanced C# programming. Happy coding!.