Software Training Institute in Chennai with 100% Placements – SLA Institute

Easy way to IT Job

Share on your Social Media

Best C Sharp Tutorial for Beginners

Published On: March 12, 2025

C# is a strong and flexible programming language that is frequently used to create desktop, online, mobile, and gaming applications. Learn important concepts in this Best C# tutorial. Learn C# programming by exploring our C Sharp course syllabus.

Getting Started to C Sharp Tutorial

C# is an object-oriented, general-purpose programming language that is easy to learn and structured. It may be compiled on multiple computer platforms and operates on Microsoft’s Net Framework. We cover the following in our C# tutorial for beginners:

  • Fundamental Concepts of C Sharp
  • Object Oriented Programming in C#
  • Advanced C# Concepts
  • .NET Ecosystem for C# Programming
  • Importance of Learning C#

Recommended: C# Online Course Program.

Fundamental Concepts of C Sharp

C# is a member of the C programming family and is comparable to other popular languages like Java and C++. It is mostly used to create web services, mobile apps, desktop apps, Windows apps, and games (using Unity Engine). The main language for creating games with the Unity engine is C#.

Data Types in C#

Data types are essential for specifying the type of data that a variable in C# can store. Value types and reference types are the two primary categories into which C# divides data types.

Value Types in C#

Value types use their own memory allocation to store the actual data. It is a copy of the value produced when a value type variable is assigned to another.

Common Value Types
CategoryData TypeDescription
Integral TypesintInteger (e.g., -10, 0, 100).
longLong integer (larger range than int).
shortShort integer.
byteUnsigned byte.
sbyteSigned byte.
uintUnsigned integer.
ulongUnsigned long integer.
ushortUnsigned short integer.
charSingle Unicode character (e.g., ‘A’, ‘1’).
Floating-Point TypesfloatSingle-precision floating-point number.
doubleDouble-precision floating-point number.
decimalHigh-precision decimal number (suitable for financial calculations).
Boolean TypeboolRepresents true or false.
StructsUser-defined value types.
EnumsUser-defined set of named constants.

Reference Types in C#

Instead of storing the actual data, reference types save a reference (memory address) to the data. Both variables point to the same data when you assign a reference type variable to another since you are copying the reference.

Common Reference Types
Data TypeDescription
ClassesClasses are user-defined types that have the ability to hold methods and data.
ObjectsObjects serve as the foundational type for all other types.
StringsA string is a collection of Unicode characters.
ArraysArrays are groups of identically typed elements.
InterfacesSpecify an agreement that classes are able to follow.
DelegatesReferences to methods.

Important Difference:

  • Memory Allocation: While reference types are usually allocated on the heap, value types are usually allocated on the stack.
  • Assignment: Assigning reference types duplicates the reference, while assigning value types duplicates the value.

Writing dependable and effective C# code requires an understanding of these data type groups.

Review your skills with our C# interview questions and answers.

Variables in C#

Variables are crucial building elements for data manipulation and storage in C#. They serve as designated memory storage spaces that contain values that are subject to change while a program is running. 

Ways to Use Variables in C# Programming

Declaration of a Variable: A variable must be declared, with its name and data type specified, before it may be used.

Example: int age, string name;

Initializing a Variable: It is about giving a variable a starting value.

Example: age = 22;, string name = “Raj”;

Declaration and initialization can be combined: int age = 22;

Data Type: The types of values that each variable can store, such as text, integers, and floating-point numbers, are determined by its particular data type.

Rules for Naming Variables:

  • Variable names ought to be distinct within their domain.
  • They may include underscores, numbers, and letters.
  • They have to begin with an underscore or letter.
  • For example, age and Age are not the same. They are case-sensitive.
  • They can’t be keywords in C#.

Types of Variables

The scope and lifetime of C# variables can be used to classify them:

Local Variables

  • Local variables are those that are specified inside a constructor, method, or code block.
  • Only the block in which they are declared is covered by them.
  • They are only present while the block is running.

Instance Variables (Non-Static Fields)

  • Non-static fields, or instance variables, are declared inside a class but outside of any methods.
  • These variables are duplicated in each instance (object) of the class.
  • They stand in for an object’s qualities.

Static Variables (Static Fields)

  • The static keyword is used to declare static variables, often known as static fields, inside a class.
  • They don’t belong to specific instances; they belong to the class.
  • Every instance of the class shares a single copy of a static variable.

Constants

  • The const keyword is used to declare them.
  • Once they are initialized, their values cannot be altered.
  • At the moment of declaration, they have to be initialized.

Readonly Variables

  • The readonly keyword is used to declare readonly variables.
  • Comparable to const, but initializable within the class’s constructor.

To avoid name conflicts and ensure that variables are available when needed, it is essential to understand variable scope. Accurate data representation and effective memory use depend on selecting the right data type.

Learn programming from scratch with our C and C++ Training in Chennai.

Operators in C#

Operators are C# symbols that manipulate operands, or variables and values. The extensive collection of operators offered by C# can be divided into the following categories:

Name of the OperatorDescriptionOperations
Arithmetic OperatorsTo perform basic mathematical operations+ (Addition)- (Subtraction)* (Multiplication)/ (Division)% (Modulo – remainder after division)++ (Increment)– (Decrement)
Assignment OperatorsTo assign values to variables= (Assignment)+= (Add and assign)-= (Subtract and assign)*= (Multiply and assign)/= (Divide and assign)%= (Modulo and assign)
Comparison/Relational Operators:These operators return a boolean value (true or false) after comparing two operands.== (Equal to)!= (Not equal to)> (Greater than)< (Less than)>= (Greater than or equal to)<= (Less than or equal to)
Logical OperatorsWhen applied to boolean operands, these operators carry out logical operations.&& (Logical AND)|| (Logical OR)! (Logical NOT)
Bitwise OperatorsIndividual bits of integer operands are subjected to operations by these operators.& (Bitwise AND)| (Bitwise OR)^ (Bitwise XOR)~ (Bitwise complement)<< (Left shift)>> (Right shift)
Conditional Operator (Ternary Operator)If-else sentences can be shortened using this operator.? : (Conditional operator)
Null-Coalescing OperatorThis operator offers a shortcut for determining whether a value is null?? (Null-coalescing operator)

Apart from these operators, there are member access operators, type testing operators, and pointer related operators. 

Important Points to Remember:

  • Operator Precedence: The order in which operators are evaluated is determined by their particular order of precedence.
  • Operator Associativity: Associativity establishes the evaluation direction (left-to-right or right-to-left) when operators share the same precedence.

Writing efficient C# code requires an understanding of these operators.

Related Training: Dot Net training in Chennai.

Control Flow in C#

The sequence in which a program’s code runs is referred to as the “control flow” in C#. It enables you to write dynamic, responsive applications with decision-making and action-repetition capabilities. The main C# control flow statements are broken out as follows:

Selection Statements (Decision Making)

if Statement: If a certain condition is true, a block of code is executed.

  • Additionally, you can use else if to check several conditions and else other to run a different piece of code if the condition is false.

switch Statement: Determines the value of an expression to determine which of several code blocks to run.

  • It is very helpful for checking a range of potential values.

Ternary Operator (? :):

  • A concise method for writing a basic one-line if-else statement.

Iteration Statements (Looping)

for loop: 

  • A for loop runs a code block a certain number of times.
  • Knowing how many times you need to repeat the loop is ideal.

while loop:

  • While a given condition is true, a while loop runs a block of code.
  • It is helpful in situations where you are unsure of the number of times the loop must execute.

Do-while Loop: 

  • This loop ensures that the code block will run at least once, much like the while loop.
  • Following the execution of the code block, the condition is verified.

foreach Loop: 

  • Iterates through a collection’s items, such as a list or array.
  • It makes it easier to access every element in a collection.

Jump Statements

  • break Statement: The break statement stops a loop or switch statement from running.
  • continue Statement: The continue statement advances to the following iteration of a loop by skipping the current one.
  • goto Statement: Control is moved to a labeled statement via the goto statement. Although goto statements are available, it is usually recommended to use them sparingly because they can make code harder to read.
  • return Statement: Ends a method’s execution and, if the method has a return type, returns a value.

Writing systems that can manage many scenarios and carry out intricate tasks requires an understanding of control flow.

Methods in C#

A unit of code that carries out a particular function is called a method. They enable you to divide intricate programs into more manageable chunks. Techniques encourage code reuse, which improves the effectiveness and maintainability of your projects.

  • Access Modifier: Establishes the method’s visibility (public, private, etc.).
  • Return Type: Indicates the kind of data that the method will return. The method uses void if it returns nothing.
  • Method Name: A special designation for the approach.
  • Parameters (optional): values that can be entered into the method.
  • Method Body: The block of code that houses the instructions the method follows is known as the method body.

Syntax for Method Declaration:

accessModifier returnType MethodName(parameterList)

{

    // Method body

    // …

    return returnValue; // If the method has a return type

}

Types of Methods

Here are the different types of methods:

  • Instance Methods: Demand that a class instance be invoked. It works with that particular instance’s data.
  • Static Methods: They are not particular to any one instance; they belong to the class itself. The class name can be used to invoke it directly.
  • Methods with Parameters: It increases their versatility by enabling you to feed data into the method.
  • Methods with Return Values: Give the calling code a value back.
  • Method Overloading: You can specify more than one method with the same name but distinct parameters by using method overloading.

Benefits of Using Methods:

  • Code Reusability: Prevents writing the same code more than once.
  • Modularity: Divides complicated programs into more manageable chunks.
  • Readability: Facilitates the comprehension and upkeep of code.
  • Organization: Enhances your code’s structure.

A fundamental component of C# programming methods must be mastered in order to create reliable and maintainable systems.

Namespaces in C#

By forming logical groupings of related types, namespaces aid in the organization of vast codebases. This facilitates the management and upkeep of intricate projects.

Namespace Declaration: The namespace keyword and the namespace name are used to define a namespace.

Example: namespace MyApplication.Utilities { … }

Nested Namespaces: A hierarchical structure can be created by nesting one namespace inside another.

Example: namespace MyApplication.Data.Access { … }

using Directive: You can avoid using fully qualified names by importing namespaces into your code using the using directive.

Example: using System;

Fully Qualified Names: A fully qualified name consists of the type name and the entire namespace hierarchy.

Example: System.Console.WriteLine()

Benefits of Using Namespaces

  • Improved Code Management: Namespaces facilitate the management of intricate and sizable codebases.
  • Reduced Naming Conflicts: They avoid naming conflicts, which might result in errors.
  • Improved Code Reusability: By offering a structured and unambiguous framework, namespaces make it easier to reuse code.

Namespaces are essentially necessary for developing C# programs that are organized and maintainable.

Suggested Course: Advanced Dot Net Training in Chennai.

Object Oriented Programming in C#

C# is a powerful and adaptable programming language, and its object-oriented design is a fundamental component of its architecture. This is an explanation of C#’s Object-Oriented Programming (OOP):

Classes and Objects

Classes are blueprints that specify action (methods), data (fields), and object creation.

Real-world entities are represented by objects, which are instances of classes.

Examples:

Consider a “Car” course. It outlines an automobile’s general attributes, such as its color, model, engine, etc.

A particular car, such as “myRedSedan,” which is an instance of the “Car” class, would be an object. Its color, model, and engine are all unique.

Encapsulation

Keeping implementation specifics and data hidden while revealing only the interfaces that are required.

public class Car

{

    // Private fields (encapsulated data)

    private string _make;

    private string _model;

    private int _year;

    // Public properties (controlled access)

    public string Make

    {

        get { return _make; }

        set { _make = value; }

    }

    public string Model

    {

        get { return _model; }

        set { _model = value; }

    }

    public int Year

    {

        get { return _year; }

        set

        {

            if (value > 1885) // Basic validation

            {

                _year = value;

            }

            else

            {

                Console.WriteLine(“Invalid year.”);

            }

        }

    }

    // Constructor

    public Car(string make, string model, int year)

    {

        Make = make; // Using properties for setting

        Model = model;

        Year = year;

    }

    // Public method (encapsulated behavior)

    public void DisplayCarDetails()

    {

        Console.WriteLine($”Make: {Make}, Model: {Model}, Year: {Year}”);

    }

}

public class Program

{

    public static void Main(string[] args)

    {

        Car myCar = new Car(“Toyota”, “Camry”, 2023);

        myCar.DisplayCarDetails();

        // Attempting to directly access private fields (not allowed)

        // myCar._make = “Honda”; // Error: _make is inaccessible

        // Using properties for controlled access

        myCar.Year = 2024;

        myCar.DisplayCarDetails();

        myCar.Year = 1800; //Demonstrates validation in the Year property.

        myCar.DisplayCarDetails(); //Year will remain 2024.

    }

}

Inheritance

Inheritance is the process of building new classes (derived classes) from preexisting classes (base classes) and gaining access to its methods and properties.

Example:

// Base class (Parent class)

public class Animal

{

    public string Name { get; set; }

    public Animal(string name)

    {

        Name = name;

    }

    public virtual void MakeSound()

    {

        Console.WriteLine(“Animal makes a sound.”);

    }

}

// Derived class (Child class) – inherits from Animal

public class Dog : Animal

{

    public string Breed { get; set; }

    public Dog(string name, string breed) : base(name) // Calls the base class constructor

    {

        Breed = breed;

    }

    public override void MakeSound() // Overrides the base class method

    {

        Console.WriteLine(“Dog barks.”);

    }

    public void Fetch()

    {

        Console.WriteLine($”{Name} fetches the ball.”);

    }

}

// Derived class (Child class) – inherits from Animal

public class Cat : Animal

{

    public Cat(string name) : base(name)

    {

    }

    public override void MakeSound()

    {

        Console.WriteLine(“Cat meows.”);

    }

    public void ClimbTree()

    {

        Console.WriteLine($”{Name} climbs a tree.”);

    }

}

public class Program

{

    public static void Main(string[] args)

    {

        Animal genericAnimal = new Animal(“Generic Animal”);

        genericAnimal.MakeSound(); // Output: Animal makes a sound.

        Dog myDog = new Dog(“Buddy”, “Golden Retriever”);

        myDog.MakeSound(); // Output: Dog barks.

        myDog.Fetch(); // Output: Buddy fetches the ball.

        Console.WriteLine($”Dog Name: {myDog.Name}, Breed: {myDog.Breed}”);

        Cat myCat = new Cat(“Whiskers”);

        myCat.MakeSound(); // Output: Cat meows.

        myCat.ClimbTree(); //Output: Whiskers climbs a tree.

        Console.WriteLine($”Cat Name: {myCat.Name}”);

        //Polymorphism example.

        Animal animalDog = new Dog(“Spot”, “Labrador”);

        animalDog.MakeSound(); //Output: Dog barks.

        Animal animalCat = new Cat(“Mittens”);

        animalCat.MakeSound(); //Output: Cat meows.

    }

}

Polymorphism

Flexibility and extensibility are made possible via polymorphism, which permits objects of different classes to be regarded as belonging to the same type.

Polymorphism example:

{

{

        Animal animalDog = new Dog(“Spot”, “Labrador”);

        animalDog.MakeSound(); //Output: Dog barks.

        Animal animalCat = new Cat(“Mittens”);

        animalCat.MakeSound(); //Output: Cat meows.

    }

}

Abstraction

Defining abstract classes and interfaces to conceal particular implementations and communicate broad ideas is known as abstraction.

Example:

// Abstract class representing a shape

public abstract class Shape

{

    // Abstract method (no implementation)

    public abstract double CalculateArea();

    // Concrete method (has implementation)

    public void DisplayShapeType()

    {

        Console.WriteLine($”This is a {this.GetType().Name}.”);

    }

}

// Derived class representing a circle

public class Circle : Shape

{

    public double Radius { get; set; }

    public Circle(double radius)

    {

        Radius = radius;

    }

    public override double CalculateArea()

    {

        return Math.PI * Radius * Radius;

    }

}

// Derived class representing a rectangle

public class Rectangle : Shape

{

    public double Width { get; set; }

    public double Height { get; set; }

    public Rectangle(double width, double height)

    {

        Width = width;

        Height = height;

    }

    public override double CalculateArea()

    {

        return Width * Height;

    }

}

public class Program

{

    public static void Main(string[] args)

    {

        // Cannot create an instance of an abstract class directly:

        // Shape myShape = new Shape(); // Error!

        Circle myCircle = new Circle(5);

        Rectangle myRectangle = new Rectangle(4, 6);

        myCircle.DisplayShapeType();

        Console.WriteLine($”Circle Area: {myCircle.CalculateArea()}”);

        myRectangle.DisplayShapeType();

        Console.WriteLine($”Rectangle Area: {myRectangle.CalculateArea()}”);

        //Polymorphism example using the abstract class.

        Shape shapeCircle = new Circle(3);

        Shape shapeRectangle = new Rectangle(5,2);

        shapeCircle.DisplayShapeType();

        Console.WriteLine($”Shape Circle Area: {shapeCircle.CalculateArea()}”);

        shapeRectangle.DisplayShapeType();

        Console.WriteLine($”Shape Rectangle Area: {shapeRectangle.CalculateArea()}”);

    }

}

Related Training: ASP Dot Net Training in Chennai.

Advanced C# Concepts

Here are some important C# advanced concepts:

Arrays and Collections: Groups of data can be stored and manipulated using arrays and collections. Arrays are collections of elements of the same type that have a fixed size. Dictionaries, lists, and other collections are dynamic repositories with a range of features.

Syntax for Arrays:

dataTypearrayName; // Declares an array of ‘dataType’

dataType[] arrayName = new dataType[size]; // Initializes an array with a specific size

dataType[] arrayName = { value1, value2, value3, … }; // Initializes an array with values

arrayName[index]; // Accesses the element at the specified index

dataType[,] arrayName = new dataType[rows, columns]; // 2D array

dataType[,,] arrayName = new dataType[x, y, z]; // 3D array

dataType[,] arrayName = { { value1, value2 }, { value3, value4 } }; //initializing with values.

Don’t forget to use the system.collections. When using List, Dictionary, or HashSet, place Generic; at the beginning of your file.

using System.Collections.Generic;

HashSet<dataType> hashSetName = new HashSet<dataType>();

HashSet<dataType> hashSetName = new HashSet<dataType>(){value1, value2, value3};

Dictionaries:

using System.Collections.Generic; // Add this namespace

Dictionary<keyDataType, valueDataType> dictionaryName = new Dictionary<keyDataType, valueDataType>();

Dictionary<keyDataType, valueDataType> dictionaryName = new Dictionary<keyDataType, valueDataType>()

{

    { key1, value1 },

    { key2, value2 },

    { key3, value3 }

};

Exception Handling

To deal with runtime errors, use the try, catch, and finally blocks. The following keywords are available in C# for managing exceptions:

try: 

  • The code that could raise an exception is enclosed in the try block.
  • It designates a piece of code that you wish to keep an eye out for mistakes in.

catch: 

  • The exceptions thrown inside the relevant try block are handled by the catch block.
  • To handle various exception kinds, you can have more than one catch block.
  • The kind of exception that each catch block can handle is specified.

finally:

  • Code that is always run, whether or not an exception is thrown, is contained in the finally block.
  • Usually, it’s employed for cleanup tasks like resource releases and file closures.

throw: 

  • To specifically throw an exception, use the throw keyword.
  • You can either make your own custom exceptions or throw built-in exceptions.

Example:

try

{

    // Code that might throw an exception

}

catch (ExceptionType1 ex)

{

    // Handle ExceptionType1

}

catch (ExceptionType2 ex)

{

    // Handle ExceptionType2

}

catch (Exception ex)

{

    // Handle any other exceptions

}

finally

{

    // Code that always executes

}

Events and Delegates

  • Delegates: Event-driven programming is made possible by delegates, which are type-safe function pointers.
  • Events: Systems for alerting objects to actions or changes in state.

Example:

public delegate void MyDelegate(string message);

public class Example

{

    public void MethodA(string text)

    {

        Console.WriteLine(“MethodA: ” + text);

    }

    public void MethodB(string text)

    {

        Console.WriteLine(“MethodB: ” + text);

    }

    public void RunDelegate(MyDelegate del, string message)

    {

        del(message);

    }

    public static void Main(string[] args)

    {

        Example ex = new Example();

        MyDelegate delA = new MyDelegate(ex.MethodA);

        MyDelegate delB = new MyDelegate(ex.MethodB);

        ex.RunDelegate(delA, “Hello from Delegate A”);

        ex.RunDelegate(delB, “Hello from Delegate B”);

    }

}

Key Differences Between Events and Delegates:

  • Delegates are references to type-safe functions. It is directly invokeable. It gives callbacks a general mechanism. 
  • Events: Delegates are used specifically for events. It offers a regulated method for publishing alerts. It implements the subscriber-publisher model. 

Delegates essentially supply the mechanism, while events offer an organized method of using it to send notifications.

LINQ

Language Integrated Query, or LINQ, is a consistent syntax for querying and modifying data from several sources.

Common LINQ Operators in C#:

  • Where(): Uses a predicate to filter a sequence.
  • Select(): Creates a new form for every element in a series.
  • OrderBy()/OrderByDescending(): Sorting a sequence’s elements is done with it.
  • GroupBy(): Assembles a sequence’s components.
  • Join(): Uses a matched key to join two sequences.
  • Any()/All(): It verifies whether any or all of the elements meet a requirement.
  • Count(): The number of elements in a sequence is returned by the count() function.
  • The functions sum(), average(), min(), and max() carry out aggregate operations.
  • FirstOrDefault()/LastOrDefault(): Returns a default value or the first or last element.
  • Take()/Skip(): A given number of components are taken or skipped using it.

Asynchronous Programming: Using async and await keywords to carry out non-blocking actions and enhance application responsiveness is known as asynchronous programming.

Example:

using System;

using System.Net.Http;

using System.Threading.Tasks;

public class AsyncExample

{

    public static async Task Main(string[] args)

    {

        try

        {

            string content = await DownloadContentAsync(“https://www.example.com”);

            Console.WriteLine(content.Substring(0, 100)); // Display first 100 characters.

        }

        catch (Exception ex)

        {

            Console.WriteLine($”Error: {ex.Message}”);

        }

    }

    public static async Task<string> DownloadContentAsync(string url)

    {

        using (HttpClient client = new HttpClient())

        {

            HttpResponseMessage response = await client.GetAsync(url);

            response.EnsureSuccessStatusCode();

            return await response.Content.ReadAsStringAsync();

        }

    }

}

Generics: Developing reusable code that is compatible with various data types is known as generics.

using System;

using System.Collections.Generic;

public class GenericExample

{

    // Generic method to swap two values of any type

    public static void Swap<T>(ref T a, ref T b)

    {

        T temp = a;

        a = b;

        b = temp;

    }

    // Generic class representing a simple container

    public class Container<T>

    {

        private T value;

        public Container(T value)

        {

            this.value = value;

        }

        public T GetValue()

        {

            return value;

        }

        public void SetValue(T newValue)

        {

            value = newValue;

        }

    }

    public static void Main(stringargs)

    {

        // Example with Swap<T> for integers

        int x = 5, y = 10;

        Console.WriteLine($”Before swap: x = {x}, y = {y}”);

        Swap(ref x, ref y); // Implicit type inference

        Console.WriteLine($”After swap: x = {x}, y = {y}”);

        // Example with Swap<T> for strings

        string str1 = “Hello”, str2 = “World”;

        Console.WriteLine($”Before swap: str1 = {str1}, str2 = {str2}”);

        Swap(ref str1, ref str2); // Implicit type inference

        Console.WriteLine($”After swap: str1 = {str1}, str2 = {str2}”);

        // Example with Container<T> for integers

        Container<int> intContainer = new Container<int>(42);

        Console.WriteLine($”Integer container value: {intContainer.GetValue()}”);

        intContainer.SetValue(99);

        Console.WriteLine($”Integer container value after set: {intContainer.GetValue()}”);

        // Example with Container<T> for strings

        Container<string> stringContainer = new Container<string>(“Generic String”);

        Console.WriteLine($”String container value: {stringContainer.GetValue()}”);

        stringContainer.SetValue(“New Generic String”);

        Console.WriteLine($”String container value after set: {stringContainer.GetValue()}”);

        //Example with a generic List.

        List<double> doubleList = new List<double>();

        doubleList.Add(1.1);

        doubleList.Add(2.2);

        doubleList.Add(3.3);

        foreach(double d in doubleList){

            Console.Write(d + ” “);

        }

        Console.WriteLine();

    }

}

Attributes: Giving code elements metadata that can be processed at runtime or during design.

Example:

using System;

// 1. Define a custom attribute

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]

public class AuthorAttribute : Attribute

{

    public string Name { get; set; }

    public string Version { get; set; }

    public AuthorAttribute(string name)

    {

        Name = name;

    }

}

// 2. Apply the custom attribute to a class

[Author(“John Doe”, Version = “1.0”)]

public class MyClass

{

    // 3. Apply the custom attribute to a method

    [Author(“Jane Smith”)]

    public void MyMethod()

    {

        Console.WriteLine(“Executing MyMethod.”);

    }

}

public class Program

{

    public static void Main(string[] args)

    {

        // 4. Use reflection to retrieve attribute information

        Type myClassType = typeof(MyClass);

        if (Attribute.IsDefined(myClassType, typeof(AuthorAttribute)))

        {

AuthorAttribute classAuthor = (AuthorAttribute)Attribute.GetCustomAttribute(myClassType, typeof(AuthorAttribute));

Console.WriteLine($”Class Author: {classAuthor.Name}, Version: {classAuthor.Version}”);

        }

System.Reflection.MethodInfo myMethodInfo = myClassType.GetMethod(“MyMethod”);

        if(Attribute.IsDefined(myMethodInfo, typeof(AuthorAttribute)))

        {

AuthorAttribute methodAuthor = (AuthorAttribute)Attribute.GetCustomAttribute(myMethodInfo, typeof(AuthorAttribute));

            Console.WriteLine($”Method Author: {methodAuthor.Name}”);

        }

    }

}

Reflection in C#

Analyzing and modifying code while it’s running.

using System;

using System.Reflection;

public class MyClass

{

    public int PublicField = 10;

    private string privateField = “Secret”;

    public MyClass() { }

    public MyClass(int value)

    {

        PublicField = value;

    }

    public void PublicMethod(string message)

    {

        Console.WriteLine($”Public Method: {message}”);

    }

    private void PrivateMethod()

    {

        Console.WriteLine(“Private Method called.”);

    }

}

public class ReflectionExample

{

    public static void Main(string[] args)

    {

        // Get the Type object for MyClass

        Type myClassType = typeof(MyClass);

        // Get information about the class

        Console.WriteLine($”Class Name: {myClassType.Name}”);

        Console.WriteLine($”Full Name: {myClassType.FullName}”);

        Console.WriteLine($”Assembly: {myClassType.Assembly.FullName}”);

        // Get constructors

        ConstructorInfo[] constructors = myClassType.GetConstructors(BindingFlags.Public | BindingFlags.Instance);

        foreach (ConstructorInfo constructor in constructors)

        {

            Console.WriteLine($”Constructor: {constructor}”);

        }

        // Create an instance of MyClass using reflection

        object myObject = Activator.CreateInstance(myClassType, new object[] { 20 }); // Example using the constructor with an int parameter.

        // Get fields

        FieldInfo publicFieldInfo = myClassType.GetField(“PublicField”, BindingFlags.Public | BindingFlags.Instance);

        FieldInfo privateFieldInfo = myClassType.GetField(“privateField”, BindingFlags.NonPublic | BindingFlags.Instance);

        if (publicFieldInfo != null)

        {

            Console.WriteLine($”Public Field Value: {publicFieldInfo.GetValue(myObject)}”);

            publicFieldInfo.SetValue(myObject, 30); // Modify the field’s value

            Console.WriteLine($”Modified Public Field Value: {publicFieldInfo.GetValue(myObject)}”);

        }

        if (privateFieldInfo != null)

        {

            privateFieldInfo.SetValue(myObject, “New Secret”);

            Console.WriteLine($”Modified Private Field Value: {privateFieldInfo.GetValue(myObject)}”);

        }

        // Get methods

        MethodInfo publicMethodInfo = myClassType.GetMethod(“PublicMethod”, BindingFlags.Public | BindingFlags.Instance);

        MethodInfo privateMethodInfo = myClassType.GetMethod(“PrivateMethod”, BindingFlags.NonPublic | BindingFlags.Instance);

        if (publicMethodInfo != null)

        {

            publicMethodInfo.Invoke(myObject, new object[] { “Hello from reflection!” });

        }

        if (privateMethodInfo != null)

        {

            privateMethodInfo.Invoke(myObject, null);

        }

    }

}

Lambda Expressions in C#

Anonymous functions called lambda expressions can be used to construct expression trees or delegates.

Example:

Func<int, int> square = x => x * x;

Console.WriteLine(square(5)); // Output: 25

Action<string> greet = name => {

    string greeting = “Hello, ” + name + “!”;

    Console.WriteLine(greeting);

};

greet(“World”); // Output: Hello, World!

Nullable Types in C#

Value types that can represent null values are known as nullable types.

Example:

using System;

public class NullableExample

{

    public static void Main(string[] args)

    {

        int? nullableInt = null;

        double? nullableDouble = 3.14;

        if (nullableInt.HasValue)

        {

            Console.WriteLine($”nullableInt value: {nullableInt.Value}”);

        }

        else

        {

            Console.WriteLine(“nullableInt is null.”);

        }

        if (nullableDouble.HasValue)

        {

            Console.WriteLine($”nullableDouble value: {nullableDouble.Value}”);

        }

        int result = nullableInt ?? -1; // Using null-coalescing operator

        Console.WriteLine($”result: {result}”);

    }

}

Tuples in C#

Multiple values can be grouped into a lightweight data structure using tuples.

Example:

using System;

public class TupleExample

{

    public static void Main(string[] args)

    {

        // Creating a tuple

        (int id, string name, double salary) employee = (1, “Bob”, 50000.0);

        // Accessing tuple elements

        Console.WriteLine($”ID: {employee.id}, Name: {employee.Name}, Salary: {employee.salary}”);

        // Deconstructing a tuple

        var (employeeId, employeeName, employeeSalary) = employee;

        Console.WriteLine($”ID: {employeeId}, Name: {employeeName}, Salary: {employeeSalary}”);

        // Returning a tuple from a method

        var result = GetEmployeeDetails();

        Console.WriteLine($”ID: {result.Id}, Name: {result.Name}, Salary: {result.Salary}”);

    }

    public static (int Id, string Name, double Salary) GetEmployeeDetails()

    {

        return (2, “Charlie”, 60000.0);

    }

}

Pattern Matching in C#

It makes it possible to use more intricate conditional reasoning.

  • Type Checking: if (obj is string s) { … }
  • Switching on Types: switch (shape) { case Circle c: … case Rectangle r: … }
  • Property Matching: if (person is { Age: >= 18 }) { … }
  • Null Checks: if (obj is null) { … }

The C# language benefits greatly from pattern matching, which makes it possible for programmers to construct more effective and maintainable code.

Recommended: Advanced Dot Net Interview Questions and Answers.

.NET Ecosystem for C# Programming

With a vast array of tools, libraries, and frameworks, the.NET ecosystem offers a rich and complete environment for C# programming. 

.NET Runtime:

  • .NET Runtime with CLR, .NET Core, Mono, and .NET Framework.
  • .NET Libraries with BCL (Base Class Library).
  • .NET Frameworks and Technologies such as ASP.NET Core, .NET MAUI (Multi-platform App UI), EF Core (Entity Framework), WinForms (Windows Forms), WPF (Windows Presentation Foundation), gRPC, and Blazor.

Development Tools:

  • Visual Studio with dedicated IDE (Integrated Development Environment).
  • Visual Studio Core for cross platform development.
  • .NET CLI (Command-Line Interface)
  • NuGet, a dedicated package manager for .NET development.

Language Features: Every version of C# adds new features, which means that the language itself is always changing. These characteristics facilitate new programming paradigms and increase developer productivity.

Suggested: ASP Dot Net Tutorial for Beginners.

Importance of Learning C#

Gaining knowledge of C# has several benefits, making it a useful ability for both novice and experienced programmers.

  • C# supports in building a wide range of applications and even it is used in developing enterprise application development.
  • C# brings strong job market demand across various industries.
  • C# is a robust language with OOPs, .NET ecosystem, and Microsoft support.
  • Easy for game development with Unity game engine.
  • It has cross-platform capabilities and strong community support.

Explore all our software courses here.

Conclusion

Essentially, mastering C# gives you a flexible and in-demand talent that allows you to pursue a variety of software development-related employment options. We hope this C# tutorial for beginners helps you gain complete understanding of C# fundamentals. Learn C# programming in our C# training institute in Chennai to kickstart your software engineer career.

Share on your Social Media

Just a minute!

If you have any questions that you did not find answers for, our counsellors are here to answer them. You can get all your queries answered before deciding to join SLA and move your career forward.

We are excited to get started with you

Give us your information and we will arange for a free call (at your convenience) with one of our counsellors. You can get all your queries answered before deciding to join SLA and move your career forward.