upGrad KnowledgeHut SkillFest Sale!

C# Interview Questions and Answers

C# is a modern, object-oriented programming language developed by Microsoft as part of the .NET platform. It is used to develop applications for the Windows operating system and is often used with the .NET Framework or .NET Core. It can also be used for cross-platform development on platforms such as macOS and Linux using .NET Core. The C# interview questions and answers are curated for beginner and advanced professionals. The questions comprise various topics like array, syntax, data types, operators, asynchronous programming, web development using C# and ASP.NET. Our set of C# interview questions will help your interview preparation more effective and that will help you be confident in the interview.

  • 4.5 Rating
  • 114 Question(s)
  • 60 Mins of Read
  • 10688 Reader(s)

Beginner

C#7.3 is the current version of C#. It is a multi-paradigm, generic and object-oriented programming languages. The following are the features:

  • Positional Arguments

Named arguments can be followed by positional arguments.

  • Ref local variables

Easily reassign ref local variables in C# 7.3

  • Stackalloc Arrays

Use initializers on stackalloc arrays.

  • Dispatch

Implement method dispatch on properties other than the object type.

  • Out Variables

A method’s out parameters can be defined directly in the method in C# 7.

  • Local Functions

You can define a function within the scope of another function. This gets local variables into the scope.

  • Deconstruction

This includes deconstruction of tuples into separate variables and creating metadata for the names of tuple elements.

  • Dummy Variables

Discards are dummy variables intentionally unused in application code. The maintainability of the code and make its intent more clear.

  • Digit Separators

These are beneficial in grouping digits in large numeric literals. These provide great readability and no significant downside.

  • Binary Literals

These are literals in binary form. They are identical to hexadecimal literals except they use digits 0 and 1 with base 2. Binary literals are great for educational purposes and are low cost implementations.

The const in C# is faster than readonly, but the performance of const is not better than readonly.

  • Const

A value with const keyword cannot change throughout the life of a program.

A const variable cannot be reassigned.

  • Readonly

A value with Readonly keyword whose value can be initialized during runtime, unlike const.

Let us now see the difference:

Basis
ConstReadonly
Local VariableCan be applied to local variables.Cannot be applied to local variables
MemoryMemory is not allocated.Dynamic memory is allocated for readonly fields.
StaticConst are by-default staticTo make it class member, include static keyword before readonly
Ref or outWe cannot pass const field as ref or out parameterThe readonly field can be passed as ref or out parameters in the constructor context.
FasterFaster than readonly.Readonly isn’t faster.
PerformancePerformance isn’t better than readonly.Performance is better than const.

This is a frequently asked question in C# interview questions for freshers.

It is a suffix set in C# that is used while declaring float. This is used to inform the compiler the type of the literal. An example:

float a = 1239f;

An object of a class is a class instance in C#. All the members of the class can be accessed using the object or instance of the class.

The definition of the class instance starts with the class name that is followed by the name of the instance. Then the new operator is used to create the new instance.

A program that demonstrates a class instance in C# is given as follows:

using System;
namespace Demo
{
  class Sum
  {
    private int x;
    private int y;
    public void value(int val1, int val2)
    {
        x = val1;
        y = val2;
    }
    public int returnSum()
    {
        return x + y;
    }
   }
   class Test
   {
     static void Main(string[] args)
     {
        Sum obj = new Sum();   
        obj.value(8, 5);
        Console.WriteLine("The sum of 8 and 5 is: {0}" , obj.returnSum());
     }
   }
}

The output of the above program is given as follows:

The sum of 8 and 5 is: 13

An array can be emptied using the Array.Clear() method. This method sets the required range of the elements in the array to their default values where the array type may be integer, boolean, class instances etc. To empty the whole array, the range of elements should simply be the length of the whole array.

A program that demonstrates the Array.Clear() method to empty the array is given as follows:

using System;
public class Demo
{
   public static void Main()
   {
       int[] arr = new int[] {3, 9, 7, 1, 6};
       Console.Write("The original integer array is: ");
       foreach (int i in arr)
       {
           Console.Write(i + " ");
       }
       Array.Clear(arr, 0, arr.Length);
       Console.Write("\nThe modified integer array is: ");
       foreach (int i in arr)
       {
           Console.Write(i + " ");
       }
   }
}

The output of the above program is given as follows:

The original integer array is: 3 9 7 1 6
The modified integer array is: 0 0 0 0 0

The “as” operator in C# is somewhat similar to the “is” operator. However, the “is” operator returns boolean values but the “as” operator returns the object types if they are compatible to the given type, otherwise it returns null.

In other words, it can be said that conversions between compatible types are performed using the “as” operator.

A program that demonstrates the ‘as’ operator in C# is given as follows:

namespace IsAndAsOperators
{
   class A
   {
       public int a;
   }
   class B
   {
       public int x;
       public double y;
   }
   class Program
   {
       static void Main(string[] args)
       {
           A obj1 = new A();
           obj1.a = 9;
           B obj2 = new B();
           obj2.x = 7;
           obj2.y = 3.5;
           System.Console.WriteLine("The object obj1 is of class A? : {0}", func(obj1));
           System.Console.WriteLine("The object obj2 is of class A? : {0}", func(obj2));
       }
       public static string func(dynamic obj)
       {
           A tempobj = obj as A;
           if (tempobj != null)
               return "This is an object of class A with value " + tempobj.a;
               return "This is not an object of class A";         
       }
   }
}

The output of the above program is given as follows:

The object obj1 is of class A? : This is an object of class A with value 9
The object obj2 is of class A? : This is not an object of class A

System.Object class in the base class for all data types in C#.NET. All classes in the .NET Framework are derived from Object. The object types can be assigned values of any other types.

The following displays object:

object ob;
obj= 5;

Let us see an example of comparing objects:

using System;
class Example
{
   static void Main()
   {
       object val = new Object();
       Console.WriteLine(val.GetType());
   }
}

The output:

System.Object

The following are the best practices to handle exceptions in C#:

  • Avoid returning error code. Instead throw exceptions to display them completely.
  • Log the exceptions to a logging library. This is done to keep track of the exceptions occurred. Log it to a file using NLog, Serilog, etc.
  • Log exceptions centrally.
  • You can also log exceptions to the database.
  • View and search all exceptions across all applications.
  • While creating your own exception classes, it would be great if you can atleast the three common constructors.
  • Windows Event Log is for logging errors and other information from applications.
  • You need to ensure that the metadata for the exceptions is available to code that is executing remotely while creating user-defined exceptions.
  • View and search all exceptions across all servers.
  • Use the Visual Studio Debugger to view all exception.
  • Uniquely identify exceptions to easily bifurcate them.

If you are not sure of the parameters in the arrays, then you can use the param type arrays. The param arrays hold n number of parameters.

The following is an example:

using System;
namespace Application {
  class Example {
     public int Display(params int[] a) {
        int mul = 1;
        foreach (int i in a) {
           mul *= i;
        }
        return mul;
     }
  }
  class Demo {
     static void Main(string[] args) {
        Example ex = new Example();
        int mul = ex.Display(3, 4, 5);
        Console.WriteLine("Result = {0}", mul);
        Console.ReadKey();
     }
  }
}

The output:

Result = 60

Here is another example of param arrays in C#:

using System;
namespace ArrayDemo
{
  class Example
  {
      static int SumOfElements(params int[] p_arr)
       {
           int sum=0;
           foreach (int i in p_arr)
           {
              sum += i;
           }
           return sum;
       }
     static void Main(string[] args)
     {
           int sum=0;
           sum = SumOfElements(4, 8, 7, 3, 1);
           Console.WriteLine("Sum of 5 Parameters: {0}", sum);
           sum = SumOfElements(5, 7);
           Console.WriteLine("Sum of 2 Parameters: {0}", sum);
           sum = SumOfElements(10, 7, 9);
           Console.WriteLine("Sum of 3 Parameters: {0}", sum);
     }
  }
}

The output of the above program is as follows:

Sum of 5 Parameters: 23
Sum of 2 Parameters: 12
Sum of 3 Parameters: 26

Common Language Runtime (CLR) is defined in the Common Language Infrastructure (CLI).

CLR is the Virtual Machine component managing the execution of programs written in languages using .NET Framework. Some of its examples include C#, F#, etc.

The .NET source code is compiled to Common Language Infrastructure (CLI). The code is executed at runtime after the CIL is converted to native code. This is done using JIT (Just-In-Compiler) compiler.

C# is designed for the Common Language Infrastructure (CLI), which describes executable code and runtime environment. This allows usage of multiple high-level languages on various computer platforms and architectures.

Some of the major differences between an Array and an ArrayList in C# are given as follows:

Array
ArrayList
A group of similar type variables that can be referred to by a common name is known as an Array.The ArrayList is a Collection that implements the IList Interface and uses an array that is dynamic.
The System .Array namespace contains Arrays.
The System.The collection namespace contains ArrayList.
An Array cannot accept a null value.
An ArrayList can accept a null value.
An Array has a fixed size and this size cannot be increased or decreased dynamically.
The size of an ArrayList can be increased or decreased dynamically.
An Array can store data of a single data type such as int, float, char etc.
An ArrayList can store data of different data types.
The insertion and deletion operation in an Array is quite fast.
The insertion and deletion operation in an ArrayList is slower as compared to an Array.
An Array is strongly typed.
An ArrayList is not strongly typed.

A program that demonstrates an Array and ArrayList in C# is given as follows:

using System;
using System.Collections;
namespace Demo
{
  class Example
  {
     static void Main(string[] args)
     {
        int[] arr = new int[5];
        arr[0] = 4;
        arr[1] = 7;
        arr[2] = 3;
        arr[3] = 9;
        arr[4] = 1;
        Console.Write("Array elements are: ");
       for (int i = 0; i < arr.Length; i++)
       {
           Console.Write(arr[i] + " ");
       }
        ArrayList arrList = new ArrayList();
        arrList.Add(5);
        arrList.Add(1);
        arrList.Add(9);
        arrList.Add(7);
        arrList.Add(4);
        Console.Write("\nArrayList elements are: ");
        foreach (int i in arrList)
        {
           Console.Write(i + " ");
        }
     }
  }
}

The output of the above program is given as follows:

Array elements are: 4 7 3 9 1
ArrayList elements are: 5 1 9 7 4

C# and C++ are both object- oriented programming languages. C# is a general purpose object-oriented programming language with multiple features such as scalability support, garbage collection, type safety, easier type declarations etc.

Some of the differences between C++ and C# are given as follows:

C++
C#
C++ code can be created for any platform.
C# code is only targeted towards the Windows operating system.
C++ provides quite a fast performance.
The C# performance is slower as compared to C++.
Manual memory management is used in C++.
Automatic garbage collection is provided in C#.
Almost anything can be coded in C++ if the syntax is correct.
Anything that is not available in the .NET framework is difficult to implement in C# as it is dependent on the .NET framework.
A low level of abstraction is provided by C++.
A high level of abstraction is provided by C#.
C++ is a light language and can be easily compiled.

C# is interpreted into bytecode and then the Common Language Runtime manages the execution.
C++ is good for using in networking, server-side applications, gaming etc.
C# is good for creating mobile, desktop, web applications.

Jagged arrays are arrays of arrays. The different arrays in a jagged array can be of many different sizes. The declaration of elements in a jagged array are given as follows:

int[ ][ ] jaggedArr = new int [5][ ];

In the above initialization, the jagged array is jaggedArr. There are 5 elements in the jagged array and each of these elements are 1-D integer arrays.

A program that demonstrates jagged arrays in C# is given as follows:

using System;
namespace Demo
{
  class Example
  {
     static void Main(string[] args)
     {
       int[][] jaggedArr = new int[5][];
       jaggedArr[0] = new int[ ] { 8, 2, 5, 1 };
       jaggedArr[1] = new int[ ] { 2, 4, 8 };
       jaggedArr[2] = new int[ ] { 8, 4, 1, 9, 4};
       jaggedArr[3] = new int[ ] { 7, 2 };
       jaggedArr[4] = new int[ ] { 6, 1, 9, 5 };
       for (int i = 0; i < jaggedArr.Length; i++)
       {
           System.Console.Write("Element {0}: ", i);
           for (int j = 0; j < jaggedArr[i].Length; j++)
           {
               System.Console.Write( jaggedArr[i][j] );
               System.Console.Write(" ");
           }
           System.Console.WriteLine();            
       }
     }
  }
}

The output of the above program is as follows:

Element 0: 8 2 5 1
Element 1: 2 4 8
Element 2: 8 4 1 9 4
Element 3: 7 2
Element 4: 6 1 9 5

Different Key-Value pairs are represented using the dictionary collection. This is somewhat similar to an English dictionary which has different words along with their meanings. The dictionary collection is included in the System.Collections.Generic namespace.

A program that demonstrates the dictionary collection in C# is given as follows:

using System;
using System.Collections.Generic;
namespace Demo
{
  class Example
  {
     static void Main(string[] args)
     {
       Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"Apple");
              dict.Add(2,"Mango");
dict.Add(3,"Orange");
dict.Add(4,"Guava");
dict.Add(5,"Kiwi");
       Console.WriteLine("The dictionary elements are given as follows:");
       foreach (KeyValuePair<int, string> i in dict)
       {
           Console.WriteLine("Key: {0}     Value: {1}", i.Key, i.Value);
       }
     }
  }
}

The output of the above program is as follows:

The dictionary elements are given as follows:
Key: 1     Value: Apple
Key: 2     Value: Mango
Key: 3     Value: Orange
Key: 4     Value: Guava
Key: 5     Value: Kiwi

The BitArray class in C# manages a compact array of bit values which are represented as boolean values where true indicates 1 (the bit is on) and false indicates 0(the bit is off).

The BitArray class is usually used if the number of bits that need to be used are not known in advance but bits are required. The bits are indexed using an integer index that starts from 0 and can be accessed using this index.

A program that demonstrates the BitArray class in C# is given as follows:

using System;
using System.Collections;
namespace BitArrayDemo
{
  class Example
  {
     static void Main(string[] args)
     {
       BitArray ba1 = new BitArray(5);
       BitArray ba2 = new BitArray(5);
       ba1.Set(0, true);
       ba1.Set(1, true);
       ba1.Set(2, false);
       ba1.Set(3, true);
       ba1.Set(4, false);
       ba2.Set(0, false);
       ba2.Set(1, true);
       ba2.Set(2, false);
       ba2.Set(3, true);
       ba2.Set(4, false);
       Console.Write("BitArray 1 is: ");
       for (int i = 0; i < ba1.Count; i++)
       {
           Console.Write(ba1[i] + " ");
       }
       Console.Write("\nBitArray 2 is: ");
       for (int i = 0; i < ba2.Count; i++)
       {
           Console.Write(ba2[i] + " ");
       }
       ba1.And(ba2);
       Console.Write("\nBitArray after AND operation is: ");
       for (int i = 0; i < ba1.Count; i++)
       {
           Console.Write(ba1[i] + " ");
       }
     }
  }
}

The output of the above program is as follows:

BitArray 1 is: True True False True False
BitArray 2 is: False True False True False
BitArray after AND operation is: False True False True False

A class is a data structure in C# that combines data variables as well as functions into a single unit. Instances of the class are known as objects. The keyword class is used to create the classes.

A structure is a data structure in C# that combines different data variables into a single unit. The keyword struct is used to create the structures. Structures are similar to classes but can be called as lighter versions of them.

Some of the differences between classes and structures are given as follows:

Classes
Structures
Classes are data structures that combine data variables as well as functions into a single unit.
Structures are data structures that combine different data variables into a single unit.
There is support for inheritance in classes.
There is no support for inheritance in structures.
Classes support constructors and can have default constructors, parameterized constructors, copy constructors etc
Structures have default and non parameter constructors that can be replaced by the user
Classes are stored on a heap.
Structures are either stored in a stack or they are inline.
Classes require the new operator for instantiation.
Structurescan be instantiated without using the new operator.
Classes are a data type in C# that are of reference type.
Structures are a data type in C# that are of value type.
Classes are used for complex data or data that is intended to be modified after the class is created.
Structures are used for small data that is not intended to be modified after the structure is created.
There are abstract classes that are used in inheritance.
There cannot be abstract structures.

Reflection provides metadata information on types, modules, assemblies etc. at runtime. It is also useful in multiple situations and this is the reason it was introduced in C#.

Some of the situations when reflections are useful in C# are given as follows:

  1. For late binding to methods and properties, reflections are quite useful.
  2. Types can be examined and instantiated in an assembly using Reflection.
  3. New types can be created at runtime using Reflections.
  4. Reflection can be used with the program metadata attributes.

A program that demonstrates the usage of System.Reflection using the GetType() method in C# is given as follows:

using System;  
using System.Reflection;  
public class Demo  
{  
   public static void Main()  
   {
       Type type1 = typeof(object[]);
       Type type2 = "this is a string".GetType();
       Type type3 = 50.GetType();  
       Console.WriteLine(type1);
       Console.WriteLine(type1.Name);
       Console.WriteLine(type2);
       Console.WriteLine(type2.Name);
       Console.WriteLine(type3);  
       Console.WriteLine(type3.Name);
   }
}

The output of the above program is as follows:

System.Object[]
Object[]
System.String
String
System.Int32
Int32

Details about Late Binding as well as Early Binding are given as follows:

  • Early Binding

The linking of a function with an object during compile time is handled by early binding. Function overloading and operator overloading are the two main techniques that implement early binding.

  • Function Overloading

There are multiple definitions for the same function name in function overloading. All these definitions can differ by the number of arguments they contain or the type of these arguments. The number and type of arguments passed are checked by the compiler at the compile time and on that basis a function is called. If there is no function that matches the parameter list at compile time, then an error is produced.

  • Operator Overloading

Many of the operators in C# can be overloaded such as unary operators (+, -, !, ++, --) , binary operators(+, -, *, /, %) etc. The functions that contain the keyword operator before the operator that is being overloaded are overloaded operators.

  • Late Binding

The linking of a function with an object during run time is handled by late binding. Late binding is implemented using abstract classes and virtual functions.

  • Abstract Classes

The base classes with partial implementation are known as abstract classes. These classes have virtual functions that are inherited by other classes to provide more functionality. The abstract methods in the abstract classes are implemented only in the derived classes. Also abstract classes cannot be instantiated.

  • Virtual Functions

Virtual functions are implemented in a different manner for different inherited classes i.e. they are redefined for the derived classes. The call to these virtual functions is decided at run time.

It's no surprise that this one pops up often in C# basic interview questions.

The thread life cycle in Java contains 5 states and the thread can be in any of these 5 states at a given time. These 5 states constitute the thread life cycle and this life cycle is started when an instance of the class System.Threading.Thread is created.

The 5 states in a thread life cycle are:

1. Unstarted

When an instance of the thread class has been created, then the thread is in the unstarted state.

2. Runnable

When the start() method is called but the thread scheduler has not selected the thread for execution, at that time the thread is in the runnable state.

3. Running

If the thread scheduler has selected a thread and it is currently running, then it is in the running state.

4. Blocked (Non-runnable)

When a thread is not eligible to run but still alive, then it is in the blocked state.

5. Terminated

The thread is in the terminated state after it has completed its execution.

Different Key-Value pairs are represented using the dictionary collection. This is somewhat similar to an English dictionary which has different words along with their meanings. The dictionary collection is included in the System.Collections.Generic namespace.

The foreach loop can be used to iterate over the dictionary in C#. A program that demonstrates this is given as follows:

using System;
using System.Collections.Generic;
namespace Demo
{
  class Example
  {
     static void Main(string[] args)
     {
       Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"James");
dict.Add(2,"Amy");
dict.Add(3,"Adam");
dict.Add(4,"Peter");
dict.Add(5,"Susan");
       Console.WriteLine("The dictionary elements are given as follows:");
       foreach (KeyValuePair<int, string> i in dict)
       {
           Console.WriteLine("Key: {0}     Value: {1}", i.Key, i.Value);
       }
     }
  }
}

The output of the above program is as follows:

The dictionary elements are given as follows:
Key: 1     Value: James
Key: 2     Value: Amy
Key: 3     Value: Adam
Key: 4     Value: Peter
Key: 5     Value: Susan

The current instance of the class is referred using the “this” keyword. Also “this” keyword can be used to access data members from constructors, instance methods etc. Another constructor can also be called from a constructor in the same class using the “this” keyword.

A program that demonstrates the usage of the “this” keyword in C# is given as follows:

using System;
namespace Demo
{
 class Student
 {
   private int rollNo;
   private string name;  
   public Student(int rollNo, string name)
   {
        this.rollNo = rollNo;
        this.name = name;  
   }
   public int returnRollNo()
   {
       return rollNo;
   }
   public string returnName()
   {
       return name;
   }
}
class program
{  
   public static void Main()
   {
       Student s = new Student(1202, "Harry Smith");
       Console.WriteLine("Roll Number: " + s.returnRollNo());
       Console.WriteLine("Name: " + s.returnName());
   }
}
}

The output of the above program is as follows:

Roll Number: 1202
Name: Harry Smith

The Count property can be used to check if a list is empty or not. This property gets the number of elements in the list. So, if the Count property gives 0 for a list, this means that the list is empty.

A program that checks if the list is empty or not using the Count property in C# is given as follows:

using System;
using System.Collections.Generic;
class Demo
{
   public static void Main()
   {
       List<int> list1 = new List<int>();
       List<int> list2 = new List<int>();
       list1.Add(7);
       list1.Add(1);
       list1.Add(5);
       list1.Add(9);
       list1.Add(3);
       if (list1.Count == 0)
       {
           Console.WriteLine("List 1 is empty");
       }
       else
       {
           Console.WriteLine("The elements in List 1 are:");
           foreach (int i in list1)
           {
               Console.WriteLine(i);
           }
       }
       if (list2.Count == 0)
       {
           Console.WriteLine("List 2 is empty");
       }
       else
       {
           Console.WriteLine("The elements in List 2 are:");
           foreach (int i in list2)
           {
               Console.WriteLine(i);
           }
       }
   }
}

The output of the above program is as follows:

The elements in List 1 are:
7
1
5
9
3
List 2 is empty

In the above program, if the list is empty then that is printed. Otherwise all the list elements are printed.

The ‘is’ operator in C# is used to check if the given object is compatible with the given type dynamically. This operator returns true if the object is compatible with the type and false otherwise i.e. it returns boolean values. If there are null objects, then ‘is’ operator returns false.

A program that demonstrates the ‘is’ operator in C# is given as follows:

namespace Demo
{
   class A
   {
       public int a;
   }
   class B
   {
       public int b;
   }
   class Program
   {
       public static void Main(string[] args)
       {
           A obj1 = new A();
           obj1.a = 5;
           B obj2 = new B();
           obj2.b = 9;
           bool flag1 = (obj1 is A);
           System.Console.WriteLine("The object obj1 is of class A ? " + flag1.ToString());
           bool flag2 = (obj2 is A);
           System.Console.WriteLine("The object obj2 is of class A ? " + flag2.ToString());
       }
   }
}

The output of the above program is given as follows:

The object obj1 is of class A ? True
The object obj2 is of class A ? False

Expect to come across this popular question in C# interview questions and answers.

The definitions for different functionalities that classes can inherit are contained in interfaces in C#. All the interface members are only declared in the interface and they need to be defined in the class that derives them.

The keyword interface is used for interface definition. Usually the interface names begin with a capital I because of common convention. Since multiple inheritance is not allowed in C#, interfaces are quite useful when a class needs to inherit functionalities from multiple sources.

A program that demonstrates working with interfaces in C# is given as follows:

using System;
namespace Demo
{
   public interface IEmployee
   {
     void display();
   }
   public class Employee: IEmployee
   {
       private int empno;
       private string name;
       public Employee(int e, string n)
       {
           empno = e;
           name = n;
       }
       public void display()
       {
           Console.WriteLine("Employee Number = {0}", empno);
           Console.WriteLine("Name = {0}", name);
           Console.WriteLine();
       }
   }
   class Test
   {
     static void Main(string[] args)
     {
        Employee e1 = new Employee(101, "James");
        Employee e2 = new Employee(102, "Susan");
        Employee e3 = new Employee(103, "Bella");
        e1.display();
        e2.display();
        e3.display();
     }
   }
}

The output of the above program is given as follows:

Employee Number = 101
Name = James

Employee Number = 102
Name = Susan

Employee Number = 103
Name = Bella

Two arrays can be compared using the SequenceEqual() method in C#. This method returns true if the two arrays are exactly the same i.e. if they are equal. Otherwise it returns false.

A program that demonstrates the comparison of two arrays using the SequenceEqual() method in C# is given as follows:

using System;
using System.Linq;
namespace Demo
{
  public class Program
  {
     public static void Main(string[] args)
     {
       int[] arr1 = new int[] {9, 5, 1, 7, 3};
       int[] arr2 = new int[] {9, 5, 1, 7, 3};
       Console.Write("Array 1: ");
       foreach(int i in arr1)
       {
           Console.Write(i + " ");
       }
       Console.Write("\nArray 2: ");
       foreach(int i in arr2)
       {
           Console.Write(i + " ");
       }
       Console.Write("\nBoth arrays are equal? " + arr1.SequenceEqual(arr2));
     }
  }
}

The output of the above program is given as follows:

Array 1: 9 5 1 7 3
Array 2: 9 5 1 7 3
Both arrays are equal? True

The #error directive is used in C# to generate an error from a particular location in the code.

An example displays the same:

using System;
namespace Example
{
class Demo
{
public static void Main(string[] args)
{
#if (!A)
   #error A is undefined
#endif
Console.WriteLine("A custom error!");
}
}
}

The #warning directive generates a level one warning from a particular location in the code. An example is displayed here:

using System;

namespace Example
{
class One
{
public static void Main(string[] args)
{
#if (!A)
    #warning A is undefined
#endif
    Console.WriteLine("A warning...");
}
}
}

C# is a general-purpose object-oriented programming language which contains multiple paradigms. There are various reasons why C# is needed as a programming language..

Some of these are given as follows:

1. Object Oriented Language

C# is an object-oriented language so the development is easier if there are long codes in large projects as compared to procedure-oriented programming languages.

2. Popularity

C# is arguably one of the most popular languages in modern times. It is used for web development, mobile development etc. Also, UWP, WPF, WinForms etc. can be used to create various Windows applications. Moreover, various applications such as Android, iOS apps can be built using the C# mobile development.

3. Structured programming language

The programs in C# can be broken into smaller parts using functions and thus structured. This makes the program easier to understand and makes C# a structured programming language.

4. Ease of Learning

C# is easy to learn and can also be easily understood. It can be mastered in a relatively short time. This is even more true for those who already have some experience with programming languages.

5. Scalable language

C# is an automatically scalable as well as updatable language. This means that the old files are regularly updated and replaced with new ones.

C# and Java are both general purpose programming languages. There are a lot of similarities as well as differences between these two languages and so choosing the correct language depends on the programmer’s need.

Differences between C# and Java

Some of the differences between C# are Java are given as follows:

  1. C# is a part of the Microsoft .NET framework and is used to develop for Microsoft platforms. Java is designed by Sun Microsystems and is widely used in open-source projects.
  2. C# uses type safe method pointers known as delegates that are used to implement event handling. Java does not contain the concept of delegates.
  3. Generics are implemented in the CLI in C# and the type information is available at runtime. Java implements generics using erasures.
  4. Common Language Runtime is used in C# while Java uses Java Virtual Machine.
  5. The enum is a list of named constants in C#. In Java, enum is the named instance of a type.
  6. The concept of class properties is only used in C# and is not supported in Java.
  7. The switch operator in C# supports string as well as constant types. On the other hand, the switch operator in Java refers to the integral or enumerated type.
  8. Operator overloading is supported in C# while it is is not supported in Java.
  9. Polymorphism is implemented in C# by using the virtual and override keywords in base class and derived class. Java implements polymorphism by default.

An object in C# is a dynamically created instance of the class that is also known as a runtime entity since it is created at runtime. All the members of the class can be accessed using the object.

The definition of the object starts with the class name that is followed by the object name. Then the new operator is used to create the object.

The syntax of the object definition is given as follows:

ClassName ObjectName = new ClassName();

In the above syntax, ClassName is the name of the class followed by the ObjectName which is the name of the object.

A program that demonstrates an object in C# is given as follows:

using System;
namespace Demo
{
  class Product
  {
    private int x;
    private int y;
    public void value(int val1, int val2)
    {
        x = val1;
        y = val2;
    }
    public int returnProduct()
    {
        return x * y;
    }
   }
   class Test
   {
     static void Main(string[] args)
     {
        Product obj = new Product();   
        obj.value(7, 3);
        Console.WriteLine("The product of 7 and 3 is: {0}" , obj.returnProduct());
     }
   }
}

The output of the above program is given as follows:

The product of 7 and 3 is: 21

Abstraction means that only the information required is visible to the user and the rest of the information is hidden from the user. This is an important part of object-oriented programming.

Abstract classes are used to implement abstraction in C#. Abstract classes are base classes that have a partial implementation. These classes have abstract methods that are inherited by other classes that provide more functionality to the methods.

A program that demonstrates abstraction is given as follows:

using System;
namespace Demo
{
   abstract class Shape
   {
     public abstract double area();
   }
   class Rectangle: Shape
   {
     private double length;
     private double breath;
     public Rectangle( double l, double b)
     {
        length = l;
        breath = b;
     }
     public override double area ()
     {
        return (length*breath);
     }
   }
    class Triangle: Shape
   {
     private double baseT;
     private double heightT;
     public Triangle( double b, double h)
     {
        baseT = b;
        heightT = h;
     }
     public override double area ()
     {
        return (0.5*baseT*heightT);
     }
  }
   class Test
   {
     static void Main(string[] args)
     {
        Rectangle r = new Rectangle(8.0, 3.0);
        Console.WriteLine("Area of Rectangle = {0}", r.area());
        Triangle t = new Triangle(2.0, 5.0);
        Console.WriteLine("Area of Triangle = {0}", t.area());
     }
   }
}

The output of the above program is as follows:

Area of Rectangle = 24
Area of Triangle = 5

The functionality of a class can be inherited by another class using inheritance. The original class is known as the base class and the class which inherits the functionality of the base class is known as the derived class.

Multilevel inheritance involves a class that inherits from a derived class. This derived class may have inherited from the base class or from another derived class and so on.

A program that demonstrates multilevel inheritance in C# is given as follows:

using System;
namespace Demo
{
    class ClassX
    {
        public int x;
        public ClassX()
        {
           x = 23;
        }
    }
    class ClassY: ClassX
    {
        public int y;
        public ClassY()
        {
            y = 91;
        }
    }
     class ClassZ: ClassY
    {
        public int z;
        public ClassZ()
        {
            z = 67;
        }
    }
   class Test
   {
     static void Main(string[] args)
     {
        ClassZ obj = new ClassZ();
        Console.WriteLine("x = {0}", obj.x);
        Console.WriteLine("y = {0}", obj.y);
        Console.WriteLine("z = {0}", obj.z);
     }
   }
}

The output of the above program is as follows:

x = 23
y = 91
z = 67

The main parts of a C# program are given as follows:

  1. Namespace declaration
  2. Class
  3. Class methods
  4. Class attributes
  5. Main method
  6. Expressions and statements
  7. Comments

A basic program that demonstrates all these parts is given as follows:

using System;
namespace Demo
{
  class Program
  {
     static void Main(string[] args)
     {
        // This program finds the sum of two numbers
        int a = 5, b = 9, c;
        c = a + b;
        Console.WriteLine("Sum of {0} and {1} is {2}", a, b, c);
     }
  }
}

The output of the above program is given as follows:

Sum of 5 and 9 is 14

Now, the various parts of the program are explained as follows:

  1. The System namespace is included in the above program with the using keyword.
  2. Then a namespace Demo is declared.
  3. Next, the class Program is declared.
  4. After that the Main() method is provided. This method is the entry point of all the C# programs.
  5. In the Main() method, a comment is provided. This is ignored by the compiler.
  6. After that, there are various statements that find the sum of two numbers.
  7. Then the sum is printed using the Console.WriteLine().

The base class for all exceptions is the System.Exception class. All of the exception classes in C# are mainly derived from the System.Exception class whether directly or indirectly. Some of the classes that are derived from the System.Exception class are System.ApplicationException and System.SystemException classes.

A program that demonstrates exception handling in C# is given as follows:

using System;
namespace Demo
{
  class Program
  {
     static void Main(string[] args)
     {
         int ans = 0;
         int num1 = 17;
         int num2 = 0;
         try
        {
           ans = num1 / num2;
        }
        catch (DivideByZeroException)
        {
           Console.WriteLine("An Exception Occured");
        }
        finally
        {
           Console.WriteLine("Answer: {0}", ans);
        }
     }
  }
}

The output of the above program is given as follows:

An Exception Occured
Answer: 0

A chain of try-catch statements to handle exceptions are Chained Exceptions in C#. To create a chain of exceptions i.e. chained exceptions:

The accessibility of a member or a type is specified using access modifiers. The four main access modifiers are given as follows:

1. public

The members that are public can be accessed without restrictions. So this is the most permissive accessibility modifier.

2. protected

The members that are protected can be accessed in the class in which they were declared or from any derived classes that were derived from the class that declared the member in question.

3. internal

The members that are internal can only be accessed from the files that are in the same assembly. Any class or a class member can be declared as internal.

4. private

The members that are private can only be accessed in the class or structure in which they were declared and not outside. So, this is the least permissive accessibility modifier.

There are six accessibility levels that can be specified from the above access modifiers. These are given as follows:

  • public

There is unrestricted access.

  • protected

The access is restricted to the containing class or the various classes and types that are derived from the containing class.

  • internal

The access is restricted to the files that are in the same assembly.

  • protected internal

The access is restricted to the various classes and types that are derived from the containing class and the files that are in the same assembly.

  • private

The access is restricted to the containing class or type.

  • private protected

The access is restricted to the containing class and types that are derived from the containing class in the same assembly.

The HashTable Collection in C# is a collection of key-value pairs. These pairs are organised using the hash code of the keys. This means that when the elements need to be accessed in the HashTable, this can be done using keys.

A program that demonstrates the HashTable Collection in C# is given as follows:

using System;
using System.Collections;
namespace Demo
{
  class Program
  {
     static void Main(string[] args)
     {
        Hashtable h = new Hashtable();
        h.Add("1", "Apple");
        h.Add("2", "Mango");
        h.Add("3", "Orange");
        h.Add("4", "Guava");
        h.Add("5", "Peach");
        h.Add("6", "Melon");
        h.Add("7", "Lychee");
        h.Add("8", "Cherry");
        ICollection allKeys = h.Keys;
        foreach (string key in allKeys)
        {
           Console.WriteLine(key + ": " + h[key]);
        }
     }
  }
}

The output of the above program is given as follows:

1: Apple
6: Melon
7: Lychee
4: Guava
5: Peach
8: Cherry
2: Mango
3: Orange

Nullable are special data types that can be assigned normal data values and null values as well. For example: Nullable<Int32> can be assigned an integer value and it can also be assigned null.

The syntax for a nullable declaration in C# is given as follows:

DataType? NameOfVariable = DataValue;

In the above syntax, DataType is the data type such as int,char, float etc. followed by ?. NameOfVariable is the variable name and the DataValue is the value assigned to the variable which can be null or any value of the specified data type.

A program that demonstrates Nullables in C# is given as follows:

using System;
namespace Demo
{
  class Example
  {
     static void Main(string[] args)
     {
        int? num1 = 4;
        int? num2 = null;
        Console.WriteLine("Value of num1 is: {0}", num1);
        Console.WriteLine("Value of num2 is: {0}", num2);
     }
  }
}

The output of the above program is as follows:

Value of num1 is: 4
Value of num2 is:

The #region direction in C# allows you to specify a block of code that can be expanded and collapsed.

You can easily use it to collapse or hide regions. This can be done to focus only on the sections of the code you are working on.

A virtual function is redefined in derived classes. It is usually used when more than the basic functionality of the function is required in the derived classes. So the virtual function has an implementation in the base class as well as in the derived classes as well. The virtual modifier cannot be used with the abstract, static, private and override modifiers.

The virtual keyword is used in the base class to create a virtual function. The override keyword is used in the derived classes to override the function.

A program that demonstrates virtual functions in C# is given as follows:

using System;
namespace Demo
{
   class Shape
   {
     public virtual double area()
     {
         return 0;
     }
   }
   class Square: Shape
   {
     private double side;
     public Square( double s)
     {
        side = s;
     }
     public override double area ()
     {
        return (side * side);
     }
   }
    class Rectangle: Shape
   {
     private double length;
     private double breath;
     public Rectangle( double l, double b)
     {
        length = l;
        breath = b;
     }
     public override double area ()
     {
        return (length * breath);
     }
  }
      class Circle: Shape
   {
     private double radius;
     public Circle( double r)
     {
        radius = r;
     }
     public override double area ()
     {
        return (3.14 * radius * radius);
     }
   }
   class Test
   {
     static void Main(string[] args)
     {
        Square s = new Square(3.5);
        Console.WriteLine("Area of Square = {0}", s.area());
        Rectangle r = new Rectangle(7.0, 2.0);
        Console.WriteLine("Area of Rectangle = {0}", r.area());
        Circle c = new Circle(4.0);
        Console.WriteLine("Area of Circle = {0}", c.area());
     }
   }
}

The output of the above program is as follows:

Area of Square = 12.25
Area of Rectangle = 14
Area of Circle = 50.24

The UnionWith() method is used to get the union of two collections. This means that all the elements in both the collections are displayed without any duplicates using the UnionWith() method.

A program that demonstrates the UnionWith() method using two dictionaries is given as follows:

using System;
using System.Collections.Generic;
public class Program
{
  public static void Main()
  {
     Dictionary < string, int > d1 = new Dictionary < string, int > ();
     d1.Add("Apple", 1);
     d1.Add("Mango", 2);
     d1.Add("Guava", 3);
     Dictionary < string, int > d2 = new Dictionary < string, int > ();
     d2.Add("Peach", 4);
     d2.Add("Apple", 5);
     HashSet < string > h = new HashSet  <string > (d1.Keys);
     h.UnionWith(d2.Keys);
     Console.WriteLine("The union of two Dictionaries is:");
     foreach(string i in h)
     {
        Console.WriteLine(i);
     }
  }
}

The output of the above program is as follows:

The union of two Dictionaries is:
Apple
Mango
Guava
Peach

Compile time polymorphism means we will declare methods with same name but different signatures because of this we will perform different tasks with same method name. This compile time polymorphism also called as early binding or method overloading

What is the difference between compile time polymorphism and run-time polymorphism?

Example: 

public class MyClass  
{  
 public int Add(int a, int b)  
 {
     return a + b;  
 }
 public int Add(int a, int b, int c)  
 {
     return a + b + c;  
 }
}

Run time polymorphism also called as late binding or method overriding or dynamic polymorphism. Run time polymorphism or method overriding means same method names with same signatures.

In this run time polymorphism or method overriding we can override a method in base class by creating similar function in derived class this can be achieved by using inheritance principle and using “virtual & override” keywords.

Example: 

public class Bclass
{
public virtual void Sample1()
{
Console.WriteLine("Base Class");
}
}
public class DClass : Bclass
{
public override void Sample1()
{
Console.WriteLine("Derived Class");
}
}
class Program
{
static void Main(string[] args)
{
DClass objDc = new DClass();
objDc.Sample1();
Bclass objBc = new DClass();
objBc.Sample1();
}
}
  • ByVal

ByVal means passing direct value to the method, which means that any change to that parameter that takes place inside that method have no affect on original data stored in argument variable.

  • ByRef

ByRef variables does not contains the data directly, it contains a reference to its data, so if the value is changed inside the method, then the same reflects in the argument variable.

Reflection is a process by which a computer program can monitor and modify its own structure and behavior. It is a way to explore the structure of assemblies at run time (classes, resources, methods). Reflection is the capability to find out the information about objects, metadata, and application details (assemblies) at run-time. We need to include System.Reflection namespace to perform reflections in C#.

Exmaple:

public class MyClass
{
   public virtual int Add(int numb1, int numb2)
   {             
       return numb1 + numb2;
   }
   public virtual int Subtract(int numb1, int numb2)
   {
       return numb1 - numb2;
   }
}
static void Main(string[] args)
{
   MyClass oMyClass = new MyClass();
   //Type information.
   Type oMyType = oMyClass.GetType();
   //Method information.
   MethodInfo oMyMethodInfo = oMyType.GetMethod("Subtract");
   Console.WriteLine("\nType information:" + oMyType.FullName);
   Console.WriteLine("\nMethod info:" + oMyMethodInfo.Name);            
   Console.Read();
}

Why we need Reflection

We need reflection for the following purposes:

  • To view attribute information at run time
  • To view the structure of assemblies at run time (classes, resources, methods)
  • It allows dynamic/late binding to methods and properties
  • In serialization, it is used to serialize and de-serialize objects
  • In web service, it is used to create and consume SOAP messages and also to generate     WSDL
  • Debugging tools can use reflection to examine the state of an object

DataReader Object in ADO.NET is a stream-based , forward-only, read-only retrieval of query results from the Data Sources , which do not update the data. The DataReader cannot be created directly from code, they can created only by calling the ExecuteReader method of a Command Object.

SqlDataReader sqlReader = sqlCmd.ExecuteReader();

The DataReader Object provides a connection oriented data access to the Data Sources. A Connection Object can contain only one DataReader at a time and the connection in the DataReader remains open, also it cannot be used for any other purpose while data is being accessed. When we started to read from a DataReader it should always be open and positioned prior to the first record. The Read() method in the DataReader is used to read the rows from DataReader and it always moves forward to a new valid row, if any row exist .

DataReader.Raed();

Below is the sample code on how to bind data to DataReader:

public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
       }
       private void button1_Click(object sender, EventArgs e)
       {
           string connetionString = null;
           SqlConnection sqlCnn ;
           SqlCommand sqlCmd ;
           string sql = null;
           connetionString = "Data Source=ServerName;Initial Catalog=DatabaseName;User ID=UserName;Password=Password";
           sql = "Your SQL Statement Here , like Select * from product";
           sqlCnn = new SqlConnection(connetionString);
           try
           {
               sqlCnn.Open();
               sqlCmd = new SqlCommand(sql, sqlCnn);
               SqlDataReader sqlReader = sqlCmd.ExecuteReader();
               while (sqlReader.Read())
               {
                   MessageBox.Show(sqlReader.GetValue(0) + " - " + sqlReader.GetValue(1) + " - " + sqlReader.GetValue(2));
               }
               sqlReader.Close();
               sqlCmd.Dispose();
               sqlCnn.Close();
           }
           catch (Exception ex)
           {
               MessageBox.Show("Can not open connection ! ");
           }
       }
   }
  • Class

A class is a user-defined blueprint or prototype from which objects are created. Basically, a class combines the fields and methods(member function which defines actions) into a single unit.

Example:

public class Author {
// Data members of class
public string name;
public string language;
public int article_no;
public int improv_no;
// Method of class
public void Details(string name, string language,
int article_no, int improv_no)
{
this.name = name;
this.language = language;
this.article_no = article_no;
this.improv_no = improv_no;
Console.WriteLine("The name of the author is : " + name
+ "\nThe name of language is : " + language
+ "\nTotal number of article published "
+ article_no + "\nTotal number of Improvements:"
+" done by author is : " + improv_no);
}
}
  • Structure

A structure is a collection of variables of different data types under a single unit. It is almost similar to a class because both are user-defined data types and both hold a bunch of different data types.

// Defining structure
public struct Car
{
// Declaring different data types
public string Brand;
public string Model;
public string Color;
}

Difference between Class and Structure

ClassStructure
Classes are of reference types.Structs are of value types
All the reference types are allocated on heap memory.All the value types are allocated on stack memory.
Allocation of large reference type is cheaper than allocation of large value type.Allocation and de-allocation is cheaper in value type as compare to reference type.
Class has limitless features.Struct has limited features.
Classes can contain constructor or destructor.Structure does not contain constructor or destructor.
Classes used new keyword for creating instances.Struct can create an instance, without new keyword
A Class can inherit from another classA Struct is not allowed to inherit from another struct or class
Function member of the class can be virtual or abstract.Function member of the struct cannot be virtual or abstract.
Two variable of class can contain the reference of the same object and any operation on one variable can affect another variable.Each variable in struct contains its own copy of data(except in ref and out parameter variable) and any operation on one variable can not effect another variable.

Intermediate

Creating a tuple with string and int items:

Tuple<int, string> t = new Tuple<int, string>(100, "john");

The following is an example:

using System;
class Example
{
   static void Main()
   {
       Tuple<int, string> t = new Tuple<int, string>(100, "john");
       if (t.Item1 == 100)
       {
           Console.WriteLine(t.Item1);
       }
       if (t.Item2 == "john")
       {
           Console.WriteLine(t.Item2);
       }
   }
}

The output:

100
John

Managed Code is managed by the CLR. The managed code compiles into machine code. Applications under the control of CLR is managed code.

The code outside the .NET Framework is called unmanaged code. Wrapper classes are used to execute the unmanaged code. Applications not under the control of CLR is managed code.

The unmanaged code is the unsafe code that use a pointer variable.

Before passing a ref parameter, you must assign it to a value. However, before passing an out parameter, you don't need to assign it to a value.

  • Ref Parameter

A reference to a memory location of a variable. declare the reference parameters using the ref keyword. A ref parameter is passed as a reference, not a value.

  • Out Parameter

With the out parameter, you can return two values from a function.

The following is an example of ref parameter:

using System;
class Example
{
   static void Main()
   {
       string str1 = "one";
       string str2 = "two";
       string str3 = "three";
       Display(ref str1);
       Display(ref str2);
       Display(ref str3);
       Console.WriteLine(str1);
       Console.WriteLine(str2);
       Console.WriteLine(str3);
   }
   static void Display(ref string a)
   {
       if (a == "two")
       {
           a = null;
       }
       if (a == "three")
       {
           a = null;
       }
   }
}

The output:

one

The following is an example of out parameter:

using System;
class Example
{
   static bool Demo(out int a)
   {
       a = 5;
       return a >= 5;
   }
   static void Main()
   {
       if (Demo(out int a))
       {
           Console.WriteLine(a);
       }
   }
}

The output would be visible correctly on .NET 4.7 and above:

5

A common question in C# basic interview questions and answers, don't miss this one.

Yes, we can display all the files in a specific directory in C#. We have to use the DirectoryInfo class. Within that, set the directory from where you want to fetch all the files:

DirectoryInfo d = new DirectoryInfo(@"D:\sid");

The GetFiles() method is then used to get all the files in an array:

FileInfo [] fileInfo = d.GetFiles();

foreach (FileInfo f in fileInfo) {
  Console.WriteLine("File Name: ", f.Name);
}

The following is an example:

using System;
using System.IO;
namespace Application {
  class Example {
     static void Main(string[] args) {
        DirectoryInfo d = new DirectoryInfo(@"D:\sid");
        FileInfo [] fileInfo = d.GetFiles();
        foreach (FileInfo f in fileInfo) {
           Console.WriteLine("File Name: ", f.Name);
        }
        Console.ReadKey();
     }
  }
}

The output displays the files in the “sid” directory:

NewOne
NewTwo
NewThree
NewFour

To set 5-item tuple in C#, set it like this:

var t = new Tuple<string, string[], int, int, int>("laptop",
     new string[] { "memoy card", "pen drive" },
     30,
     40,
     50);

Above, the tuple has string, string array, and three integer tuples. Therefore, making it a 5-item tuple.

The following is an example:

using System;
class Example {
  static void Main() {
     var t = new Tuple<string, string[], int, int, int>("laptop",
     new string[] { "memoy card", "pen drive" },
     30,
     40,
     50);
     Console.WriteLine("Tuple Item 1 = "+t.Item1);
     Console.WriteLine("Tuple Item 4 = "+t.Item4);
     Console.WriteLine("Tuple Item 5 = "+t.Item5);
  }
}

The output:

Tuple Item 1 = laptop
Tuple Item 4 = 40
Tuple Item 5 = 50

The dispose() method is called to free unmanaged resources. An example of these resources is files. However, finalize() method called by garbage collector to free unmanaged resources. An example of these resource is files. The dispose() method is called implicitly, whereas the finalize() method called explicitly.

It's no surprise that this one pops up often in C# coding interview questions.

To create a Quadruple Tuple, you need to create a tuple with 4 items. The Tuple.Create() method is used for this purpose:

var t = Tuple.Create(5, 10, 15, 20);

The following is an example:

using System;
public class Example {
  public static void Main() {
     var t = Tuple.Create(5, 10, 15, 20);
     Console.WriteLine("Item1 = "+ t.Item1);
     Console.WriteLine("Item2 = "+ t.Item2);
     Console.WriteLine("Item3 = "+ t.Item3);
     Console.WriteLine("Item4 = "+ t.Item4);
  }
}

The output:

Item1 = 100
Item2 = 200
Item3 = 300
Item4 = 400

Exceptions in C# are represented by classes. The System.Exception class has all the classes to handle exceptions.

Let us see some of the classes under the System.Exception class:

  • System.IO.IOException: Handles I/O errors.
  • System.IndexOutOfRangeException: Handles errors generated when a method refers to an array index out of range.
  • System.ArrayTypeMismatchException: Handles errors generated when type is mismatched with the array type.
  • System.NullReferenceExceptionHandles errors generated from referencing a null object.
  • System.DivideByZeroException: Handles errors generated from dividing a dividend with zero.
  • System.InvalidCastException: Handles errors generated during typecasting.
  • System.OutOfMemoryException: Handles errors generated from insufficient free memory.

Yes, in C#, you can easily display a multiline string. For that, use @.

using System;
namespace Application {
  class Example {
     static void Main(string[] args) {
        string s = @"Jack,
        What an amazing work
        efficiency!";
        Console.WriteLine("Multi-line string = "+s);
     }
  }
}

The output:

Multi-line string = Jack,
        What an amazing work
        efficiency!

To get the last three characters, use the String Substring() method. The parameter to be set under it should be “Length - 3” i.e. the last three characters. A program that obtains the last 3 characters from a string is given as follows:

using System;
public class Demo
{
public static void Main()
{
    string str = "This is an example";
    string resultStr = str.Substring(str.Length - 3);
    Console.WriteLine("Original string: {0}", str);
    Console.WriteLine("Resultant string: {0}", resultStr);
}
}

The output of the above program is as follows:

Original string: This is an example
Resultant string: ple

Expect to come across this popular question in C# programming interview questions.

To check whether a node is in a Linked List or not, the best way is to use the Contains() method.

The Contains() method has a parameter that is the value you are searching for in a Linked List:

Contains(Value) 

The method returns a Boolean Value. If a node is found in the Linked List, TRUE is returned.

Let us see an example:

using System;
using System.Collections.Generic;
class Demo
{
   static void Main()
   {
       string [] devices = {"Smartphones","Smartwatches"};
       LinkedList<string> myList = new LinkedList<string>(devices);                
        foreach (var d in myList)  
       {
           Console.WriteLine(d);  
       }
       Console.WriteLine("Smartphones in the list?: "+myList.Contains("Smartphones"));
   }
}

The output:

Smartphones
Smartwatches
Smartphones in the list?: True

A string can be converted to an integer using the int.TryParse() method. This method returns false if the string cannot be converted into an integer.

A program that demonstrates the int.TryParse() method to convert a string into int in C# is given as follows:

using System.IO;
using System;
class Demo
{
  public static void Main()
  {
     int num1, num2;
     string str1 = "20";
     string str2 = "apple";
     if (int.TryParse(str1, out num1))
       Console.WriteLine("The string 1 in int form is: " + num1);
     else
       Console.WriteLine("String 1 could not be parsed.");
     if (int.TryParse(str2, out num2))
       Console.WriteLine("The string 2 in int form is: " + num2);
     else
       Console.WriteLine("String 2 could not be parsed.");
  }
}

The output of the above program is given as follows:

The string 1 in int form is: 20
String 2 could not be parsed.

In the above program, the string str1 is converted into int and stored in num1. However, the string str2 cannot be converted into int as the string is not of a valid format.

IndexOutOfRangeException occurs when an element is tried to access with an index, which is outside the bounds of the array.

The following error message is visible:

System.IndexOutOfRangeException: Index was outside the bounds of the array

An example displays the same exception that occurs because we are trying to access an element with an index outside the bounds of the array:

using System;
namespace Example {
  class One {
     static void Main(string[] args) {
         try {
                int i;
                int [] val = new int[2] {97, 49};
                for (i = 0; i < 5; i++ ) {
                   Console.WriteLine(val[i]);
                }
          }
          catch (System.IndexOutOfRangeException indexException)
           {
               Console.WriteLine(indexException);
           }
     }
  }
}

It displays the same error as output:

97
49
System.IndexOutOfRangeException: Index was outside the bounds of the array

C# already provides Exists() method to check the existence of a file in a directory. Let us see the code in C#

using System;
using System.IO;
public class Example
{
   public static void Main()
   {     
       if (File.Exists(@"C:\jacob.txt"))
       {
           Console.WriteLine("File do exist!");
       }
      else
       {
           Console.WriteLine("File does not exist!");
       }
   }
}

Under Circular References, two or more resources causes the lock condition. These resources are interdependent on each other and these are made unusable.

The unqualified string name of a variable, member type etc. can be obtained using the nameof keyword. While renaming the definitions, the code can be kept valid using the nameof keyword. This is a compile-time feature.

A program that demonstrates the nameof keyword in C# is given as follows:

using System;
class Demo
{
   public static void Main()
   {
       int number = 60;
       Console.WriteLine(nameof(number));
       Console.WriteLine(number);
       var fruit = "cherry";
       Console.WriteLine(nameof(fruit));
       Console.WriteLine(fruit);
   }
}

The output of the above program is as follows:

number
60
fruit
cherry

The File.Exists() method is used in C# to check if a file exists or not.

In the parameter, set the name and path of the file you want to check exist or not.

File.Exists(@"C:\One.txt")

The following is an example:

using System;
using System.IO;
class Example {
  static void Main() {
     if (File.Exists(@"C:\One.txt")) {
        Console.WriteLine("File exists!");
     } else {
        Console.WriteLine("File does not exist!");
     }
  }
}

The output:

File foes not exist!

The scope of variables specifies the program parts where the variable is accessible. There are mainly three categories for the scope of variables. These are given as follows:

Class Level Scope

The variables with class level scope are accessible anywhere in the class. These variables are those that were declared inside the class but outside any method.

A program that demonstrates the variables with class level scope is given as follows:

using System;
class A
{
   int a = 10;
   public void printa()
   {
       Console.WriteLine("a = " + a);
   }
}
class Demo
{
   public static void Main()
   {
       A obj = new A();
       obj.printa();
   }
}

The output of the above program is as follows:

a=10

In the above program, the scope of the variable a is class level scope.

Method Level Scope

The variables with method level scope are accessible in the method only and not outside it. These variables are those that were declared inside the method.

A program that demonstrates the variables with method level scope is given as follows:

using System;
class Demo
{   
   public void printb()
   {
       int b = 20;
       Console.WriteLine("b = " + b);
   }
   public static void Main()
   {
       Demo obj = new Demo();
       obj.printb();
   }
}

The output of the above program is as follows:

b=20

In the above program, the scope of the variable b is method level scope.

Block Level Scope

The variables with block level scope are accessible in the block only and not outside it. These variables are normally declared in loops such as for loop, while loop etc.

A program that demonstrates the variables with block level scope is given as follows:

using System;
class Demo
{   
   public static void Main()
   {
       for (int i = 1; i <= 5; i++)
       {
           Console.Write(i + " ");
       }
   }
}

The output of the above program is as follows:

1 2 3 4 5

In the above program, the scope of the variable i is block level scope as it is only accessible inside the for loop.

The Union() method performs the union of two collections. The resultant collection contains all the elements from both the collections but there are no duplicates. Also, The namespace System.Linq is required for the Union() method.

A program that demonstrates the union of two lists using the Union() method is given as follows:

using System;
using System.Collections.Generic;
using System.Linq;
class Demo
{
   public static void Main()
   {
       List<int> list1 = new List<int>();
       list1.Add(4);
       list1.Add(1);
       list1.Add(8);
       list1.Add(2);
       list1.Add(3);
       List<int> list2 = new List<int>();
       list2.Add(9);
       list2.Add(1);
       list2.Add(3);
       list2.Add(7);
       list2.Add(2);
       var union = list1.Union(list2);
       Console.WriteLine("The elements in the union of the two lists are:");
       foreach (int i in union)
       {
           Console.WriteLine(i);
       }
   }
}

The output of the above program is as follows:

The elements in the union of the two lists are:
4
1
8
2
3
9
7

Sealed classes are used to restrict inheritance. In other words, sealed classes are those classes that cannot be extended and no class can be derived from them. The sealed keyword is used to create a sealed class in C#.

A program that demonstrates sealed classes in C# is given as follows:

using System;
sealed class Product
{
   public int returnProduct(int num1, int num2)
   {
       return num1 * num2;
   }
}
class Demo
{
   static void Main(string[] args)
   {
       Product obj = new Product();
       Console.WriteLine("The product of 3 and 5 is: " + obj.returnProduct(3,5));
   }
}

The output of the above program is as follows:

The product of 3 and 5 is: 15

In the above program, the class Product is sealed class. This means that it cannot be inherited and an error will be generated if a class is derived from class Product.

The array elements in C# can be ordered using the Array.Sort() method. This method orders the array elements and can modify the array in its place. Also, different types of array elements can be handled by Array.Sort() like integers, strings etc.

A program that demonstrates the ordering of array elements using Array.Sort() method is given as follows:

using System;
namespace Demo
{
  public class Program
  {
     public static void Main(string[] args)
     {
       int[] arr = { 23, 67, 71, 9, 57, 35, 99, 85, 25, 1 };
       Console.Write("The original array is: ");
       foreach (int i in arr)
       {
           Console.Write(i + " " );
       }
       Array.Sort(arr);
       Console.Write("\nThe sorted array is: ");
       foreach (int i in arr)
       {
           Console.Write(i + " " );
       }
     }
  }
}

The output of the above program is given as follows:

The original array is: 23 67 71 9 57 35 99 85 25 1
The sorted array is: 1 9 23 25 35 57 67 71 85 99

The OrderBy clause in C# allows the elements in the collection to be sorted in ascending order or descending order as required based on specified fields. Also multiple keys can be specified to make more secondary sort operations if they are required. Also, the sorting using the OrderBy clause is in ascending order by default.

A program that demonstrates the OrderBy clause in C# is given as follows:

using System;
using System.Linq;
using System.Collections.Generic;
public class Fruit
{
public string Name { get; set; }
}
public class Demo
{
public static void Main()
{
IList<Fruit> fruitList = new List<Fruit>()
{
new Fruit() { Name = "Orange" } ,
new Fruit() { Name = "Mango" } ,
new Fruit() { Name = "Apple" } ,
new Fruit() { Name = "Peach" } ,
new Fruit() { Name = "Guava" } ,
};
var sortAscendingOrder = from f in fruitList
                  orderby f.Name
                  select f;
var sortDescendingOrder = from f in fruitList
                  orderby f.Name descending
                  select f;
Console.WriteLine("Fruit Names in Ascending Order:");
foreach (var i in sortAscendingOrder)
        Console.WriteLine(i.Name);
Console.WriteLine("\nFruit Names in Descending Order:");
foreach (var i in sortDescendingOrder)
        Console.WriteLine(i.Name);
}
}

The output of the above program is given as follows:

Fruit Names in Ascending Order:
Apple
Guava
Mango
Orange
Peach

Fruit Names in Descending Order:
Peach
Orange
Mango
Guava
Apple

Custom exceptions can be created by users as required by inheriting the exception class. Custom exceptions are usually created if the user needs are not met by any of the predefined exceptions.

A custom exception that is thrown if the age provided is negative is given as follows:

using System;
namespace Demo
{
  class Program
  {
     static void Main(string[] args)
     {
        Age obj = new Age();
        try
        {
           obj.agePrint();
        }
        catch(GivenAgeIsNegativeException e)
        {
           Console.WriteLine("GivenAgeIsNegativeException: {0}", e.Message);
        }
     }
  }
}
public class GivenAgeIsNegativeException: Exception
{
  public GivenAgeIsNegativeException(string message): base(message)
  {
  }
}
public class Age
{
  int age = -20;
  public void agePrint()
  {
     if(age < 0)
     {
        throw (new GivenAgeIsNegativeException("Error!!! Age cannot be negative"));
     }
     else
     {
        Console.WriteLine("The age is: {0}", age);
     }
  }
}

The output of the above program is as follows:

GivenAgeIsNegativeException: Error!!! Age cannot be negative

Singleton Class allow for single allocations and instances of data. It has a private constructor preventing class from being instantiated

Two lists can be joined using the AddRange() method. This method adds the elements of the specified list or collection at the end of the given list. The parameter of the AddRange() method is the list or collection whose elements are added at the end of the list. This  list or collection can have elements that are null but it itself cannot be null.

A program that demonstrates the join of two lists using the AddRange() method is given as follows:

using System;
using System.Collections.Generic;
class Demo
{
   public static void Main()
   {
       List<int> list1 = new List<int>();
       list1.Add(7);
       list1.Add(1);
       list1.Add(5);
       list1.Add(9);
       list1.Add(3);
       List<int> list2 = new List<int>();        
       list2.Add(1);
       list2.Add(6);
       list2.Add(4);
       list1.AddRange(list2);
       Console.WriteLine("The elements in list 1 are:");
       foreach (int i in list1)
       {
           Console.WriteLine(i);
       }
   }
}

The output of the above program is as follows:

The elements in list 1 are:
7
1
5
9
3
1
6
4

A singly linked list is a linear data structure in which each node contains the data as well as the pointer or reference to the next node in the list. There is no pointer or reference to the previous node in the singly linked list.

A program that demonstrates traversal in a singly linked list is given as follows:

using System;
namespace Demo
{
   class singlelinkedlist
   {
       private int data;
       private singlelinkedlist next;
       public singlelinkedlist()
       {
           data = 0;
           next = null;
       }
       public singlelinkedlist(int num)
       {
           data = num;
           next = null;
       }
       public singlelinkedlist InsertLast(int num)
       {
           singlelinkedlist newnode = new singlelinkedlist(num);
           if (this.next == null)
           {
               newnode.next = null;
               this.next = newnode;
           }
          else
           {
               singlelinkedlist temp = this.next;
               newnode.next = temp;
               this.next = newnode;
           }
           return newnode;
       }
       public void traversal(singlelinkedlist node)
       {
           if (node == null)
               node = this;
           System.Console.WriteLine("The linked list elements are:");
           while (node != null)
           {
               System.Console.WriteLine(node.data);
               node = node.next;
           }
       }
   }
   class Program
   {
       static void Main(string[] args)
       {
           singlelinkedlist node1 = new singlelinkedlist(9);
           singlelinkedlist node2 = node1.InsertLast(1);
           singlelinkedlist node3 = node2.InsertLast(5);
           singlelinkedlist node4 = node3.InsertLast(7);
           singlelinkedlist node5 = node4.InsertLast(2);
           node1.traversal(null);
       }

The output of the above program is as follows:

The linked list elements are:
9
1
5
7
2

Two lists can be intersected using the Enumerable.Intersect() method in C#. These methods provide the common elements from both the lists as result. The namespace System.Linq is required for the Enumerable.Intersect() method.

A program that demonstrates the intersection of two lists is given as follows:

using System;
using System.Collections.Generic;
using System.Linq;
class Demo
{
   public static void Main()
   {
       List<int> list1 = new List<int>();
       list1.Add(7);
       list1.Add(1);
       list1.Add(5);
       list1.Add(9);
       list1.Add(3);
       List<int> list2 = new List<int>();
       list2.Add(9);
       list2.Add(6);
       list2.Add(4);
       list2.Add(1);
       list2.Add(7);
       var intersection = list1.Intersect(list2);
       Console.WriteLine("The elements in the intersection of the two lists are:");
       foreach (int i in intersection)
       {
           Console.WriteLine(i);
       }
   }
}

The output of the above program is as follows:

The elements in the intersection of the two lists are:
7
1
9

The int value can be obtained from enum by simply casting the enum. This process is successful because int is the default underlying type for enum. Similarly, for enums with different underlying types such as uint, ulong etc. the cast should be the type of enum.

A program that gets the int value from Enum is given as follows:

using System;
public class Demo
{  
  public enum Fruits { Apple, Mango, Orange, Peach, Melon }    
  public static void Main()
  {
     int num1 = (int)Fruits.Apple;  
     int num2 = (int)Fruits.Mango;  
     int num3 = (int)Fruits.Orange;  
     int num4 = (int)Fruits.Peach;  
     int num5 = (int)Fruits.Melon;  
     Console.WriteLine("Apple: " + num1);  
     Console.WriteLine("Mango: " + num2);  
     Console.WriteLine("Orange: " + num3);  
     Console.WriteLine("Peach: " + num4);  
     Console.WriteLine("Melon: " + num5);  
  }
}

The output of the above program is as follows:

Apple: 0
Mango: 1
Orange: 2
Peach: 3
Melon: 4

Advanced

The System.OutOfMemoryException occurs when enough memory is not allocated.

Let us see an example:

using System;
using System.Text;
namespace Application {
  class Example {
     static void Main(string[] args) {
        try {
           string deptname = "Tom";
           string loc = "North";
           StringBuilder s = new StringBuilder(deptname.Length, deptname.Length);
           s.Append(deptname);
           s.Insert(value: loc, index: deptname.Length - 1, count: 1);
        } catch (System.OutOfMemoryException e) {
           Console.WriteLine("The following is the error:");
           Console.WriteLine(e);
        }
     }
  }
}

The example displays the Out Of Memory Exception:

The following is the error:
System.OutOfMemoryException: Out of memory
 at System.Text.StringBuilder.Insert (System.Int32 index, System.String value, System.Int32 count) [0x00065] in <902ab9e386384bec9c07fa19aa938869>:0
 at Application.Example.Main (System.String[] args) [0x0002f] in <98ee8a52b3134b0799d382272292200f>:0

The SequenceEqual() method is used in C# to check whether two sequences are equal or not.

The following is an example:

using System;
using System.Linq;
class Example
{
   static void Main()
   {
       string[] arr1 = { "one", "two", "three" };
       string[] arr2 = { "one", "four", "five" };
       bool res = arr1.SequenceEqual(arr2);
       Console.WriteLine(res);
   }
}

The output:

False

Let us see another example:

using System;
using System.Linq;
class Example
{
   static void Main()
   {
       string[] arr1 = { "HTML", "CSS", "JavaScript" };
       string[] arr2 = { "HTML", "CSS", "JavaScript" };
       bool res = arr1.SequenceEqual(arr2);
       Console.WriteLine(res);
   }
}

The output:

True

Unsurprisingly, this one often pops up in C# interview questions for experienced professionals.

The Main Thread is the first thread that is created and executed inside a process. It is automatically created when the process starts execution.

A program that demonstrates the Main thread is given as follows:

using System;
using System.Threading;
namespace MultithreadingDemo
{
  class Example
  {
     static void Main(string[] args)
     {
        Thread myThread = Thread.CurrentThread;
        myThread.Name = "Main_Thread";
        Console.WriteLine("This thread is the {0}", myThread.Name);
     }
  }
}

The output of the above program is as follows:

This thread is the Main_Thread

Now let us understand the above program.

The CurrentThread property of the Thread class is used to access the Main thread. The name of the thread is specified is Main_Thread. After that, this is displayed. The code snippet for this is given as follows:

Thread myThread = Thread.CurrentThread;
myThread.Name = "Main_Thread";         
Console.WriteLine("This thread is the {0}", myThread.Name);

The Array.SyncRoot property gets an object used to synchronize access to the Array. Use the SyncRoot property to implement their own synchronization. This usage is for classes having arrays.

A default constructor takes no arguments. Each object of the class is initialized with the default values that are specified in the default constructor. Therefore, it is not possible to initialize the different objects with different values.

An example that demonstrates a default constructor is given as follows:

using System;
namespace DefaultConstructorDemo
{
  class Sum
  {
    private int x;
    private int y;
    public Sum()
    {
        x = 5;
        y = 7;
    }
    public int getSum()
    {
        return x + y;
    }  
   }
   class Test
   {
     static void Main(string[] args)
     {
        Sum s = new Sum();   
        Console.WriteLine("Sum: {0}" , s.getSum());
     }
   }
}

The output of the above program is as follows:

Sum: 12

Now let us understand the above program.

First, the class Sum is initialized. It contains two private variables x and y. The default constructor Sum() initializes x and y to 5 and 7 respectively. Then the function getSum() returns the sum of x and y. The code snippet for this is given below:

class Sum
  {
    private int x;
    private int y;
    public Sum()
    {
        x = 5;
        y = 7;
    }
    public int getSum()
    {
        return x + y;
    }
   }

The main() function is in the class Test. It initializes an object s of class Sum. Then the sum of 5 and 7 is displayed using getSum(). The code snippet for this is given below:

class Test
   {
     static void Main(string[] args)
     {
        Sum s = new Sum();   
        Console.WriteLine("Sum: {0}" , s.getSum());
     }
   }

Assign a null value to variable with nullable data types. It was introduced in C# 2.0 for the same purpose as well as assign values other than null. An example: 

int? a = null;

Above, we have assigned a null value to a variable.

A method without a name is Anonymous Method. It is defined using the delegate keyword.

The Anonymous methods can be assigned to a variable of delegate type. It can also be passed as a parameter. Here are some of the features of Anonymous Methods in C#:

  • Anonymous methods are defined using the delegate keyword.
  • Anonymous methods can be used in event handling.
  • Any unsafe codes cannot be accessed inside anonymous methods.
  • Variables declared outside the anonymous methods can be accessed inside them.
  • Variables declared inside the anonymous methods cannot be accessed outside them.
  • Anonymous methods can be passed as parameters.

The following is an example:

using System;
public delegate void DemoDelegate(int value);
public class Example
{
  public static void Display(DemoDelegate one,int a)
   {
       a *= 50;
       one(a);
   }
   public static void Main(string[] args)
   {
       Display(delegate(int a) { Console.WriteLine("Anonymous method = {0}", a); }, 100);
   }
}

The output: 

Anonymous method = 5000 

Let us see another example: 

using System;
namespace AnonymousMethodDemo
{
  class Example {
     public delegate void sum(int x, int y);
     static void Main(string[] args)
     {
        sum s = delegate(int x, int y)
        {
          Console.WriteLine("Inside Anonymous method");
          Console.WriteLine("Sum = {0}",x + y);
        };
        s(7, 12);
     }
  }
}

The output of the above program is as follows:

Inside Anonymous method
Sum = 19

The concept of Mixed arrays is obsolete since .NET 4.0. Since it does not exist now, you can use List collection in C#.

An example is:

Tuple<int, string> t = new Tuple<int, string>(200, "This is fine!"); 

A staple in C# interview questions for experienced, be prepared to answer this one.

If a Delegate invokes multiple methods, these are called Multicast Delegates.

Let us see an example:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
delegate void DemoDelegate();  
class Example  
{  
   static public void One()  
   {
       Console.WriteLine("One");  
   }
   static public void Two()  
   {
       Console.WriteLine("Two");  
   }
   static public void Three()  
   {
       Console.WriteLine("Three");  
   }
}  
class Demo  
{  
   public static void Main()  
   {
       DemoDelegate d1 = new DemoDelegate(Example.One);  
       DemoDelegate d2 = new DemoDelegate(Example.Two);  
       DemoDelegate d3 = new DemoDelegate(Example.Three);  
       DemoDelegate d4 = d1 + d2 + d3;  
       DemoDelegate d5 = d2 + d3 + d4;  
       DemoDelegate d6 = d3 - d4 + d5;
       d3();
       d4();
       d5();
       d6();
   }
}

The output:

Three
One
Two
Three
Two
Three
One
Two
Three
Two
Three
One
Two
Three

The major difference between Typeof() and GetType() is that while Typeof() obtains the type based on the class, GetType() obtains the type based on the object. Details about both of them in C# are given as follows:

  • Typeof()

The Typeof() method is used to get the System.Type object for a given type. Also, this method can be used on open generic types but it cannot be overloaded.

A program that demonstrates the Typeof() method in C# is given as follows:

using System;
using System.IO;
class Demo
{
   public static void Main()
   {
       Console.WriteLine(typeof(int));
       Console.WriteLine(typeof(char));
       Console.WriteLine(typeof(double));
       Console.WriteLine(typeof(int[]));
       Console.WriteLine(typeof(Array));
       Console.WriteLine(typeof(Stream));
       Console.WriteLine(typeof(TextWriter));
   }
}

The output of the above program is as follows:

System.Int32
System.Char
System.Double
System.Int32[]
System.Array
System.IO.Stream
System.IO.TextWriter
  • GetType()

The GetType() method obtains the type of the current object of the class. A program that demonstrates the GetType() method in C# is given as follows:

using System;
class Animal
{
}
class Mammal : Animal
{
}
class Human : Mammal
{
}
class Demo
{
   static void Main()
   {
       Animal obj1 = new Animal();
       Animal obj2 = new Mammal();
       Animal obj3 = new Human();
       Console.WriteLine(obj1.GetType());
       Console.WriteLine(obj2.GetType());
       Console.WriteLine(obj3.GetType());
   }
}

The output of the above program is as follows:

Animal
Mammal
Human

There are no final variables in C# as the keyword final is available in Java and not in C#. The keywords readonly and sealed in C# have the same implementation as final in Java.

Details about readonly and sealed in C# are given as follows:

  • The readonly keyword

In a field declaration, the readonly keyword specifies that assignment for a field can only occur with declaration or using the constructor of the same class. A program that demonstrates the readonly keyword is given as follows:

using System;
class Student
{
   readonly int rollNo;
   public Student(int rno)
   {
       rollNo = rno;
   }
   public int getRollNumber()
   {
       // rollNo = 7;
       return this.rollNo;
   }
}
public class Demo
{
   public static void Main()
   {
       Student s = new Student(105);
       Console.WriteLine("Roll Number: " + s.getRollNumber());
   }
}

The output of the above program is as follows:

Roll Number: 105

In the above program, the variable rollNo is readonly and so it cannot be assigned a value in method getRollNumber(). So if the comments are removed, an error would be obtained.

  • The sealed keyword

The sealed keyword is used in classes to restrict inheritance. So sealed classes are those classes that cannot be extended and no class can be derived from them.

A program that demonstrates the sealed keyword in C# is given as follows:

using System;
sealed class A
{   
   int a = 5;
   public int returna()
   {
       return a;
   }
}
class Demo
{
   static void Main(string[] args)
   {
       A obj = new A();
       Console.WriteLine("a = " + obj.returna());
   }
}

The output of the above program is as follows:

a = 5

In the above program, the class A is a sealed class. This means that it cannot be inherited and an error will be generated if any class is derived from the class A.

The rank of an array is the number of dimensions of an array. For example - The rank of a one-dimensional array is 1, the rank of a two dimensional array is 2 and so on. The rank of a jagged array is 1 as it is a one-dimensional array. The rank of any array can be found using the Array.Rank property.

A program that demonstrates the rank of an array in C# is given as follows:

using System;
namespace Demo
{
   class Program
   {
       static void Main(string[] args)
       {
           int[] arr1 = new int[10];
           int[,] arr2 = new int[4, 5];
           int[][] arr3 = new int[5][];
           Console.WriteLine("Rank of Array 1 is: " + arr1.Rank);
           Console.WriteLine("Rank of Array 2 is: " + arr2.Rank);
           Console.WriteLine("Rank of Array 3 is: " + arr3.Rank);
       }
   }
}

The output of the above program is as follows:

Rank of Array 1 is: 1
Rank of Array 2 is: 2
Rank of Array 3 is: 1

C# is a general purpose object-oriented programming language with multiple paradigms. It was designed for Common Language Infrastructure (CLI) in 2000 by Microsoft.

C# has multiple advantages to contribute to the speed of web development solutions. Some of these are  scalability support, garbage collection, type safety, easier type declarations etc.

Best Practices to write better C# code

Some of the best practices that help in writing better C# code are given as follows:

  1. Pascal casing should be used for method names and class names while Camel Casing should be used for local variables and method arguments.
  2. Underscore should not be used in identifiers.
  3. All member variables should be declared at the class top and at the topmost should be static variables.
  4. The class sizes should be small for greater efficiency.
  5. There should be no obsolete comments in the code. They should be updated if required.
  6. The methods should be short.
  7. There should be no unnecessary regions in the class.
  8. The complex expressions should be avoided.
  9. In a particular routine, there should be minimum number of returns.

In method overriding, the parameters are the same. In method overloading, the parameters are different.

To perform Interning of strings, use the Intern() method. Use interning to optimize application’s memory. The common language runtime conserves string storage by maintaining a table, called the intern pool.

The intern() method retrieves the reference to the particular string. The search for a string equal to the particular String is done in Intern Pool.

Unsafe code in general is a keyword that denotes a code section that is not handled by the Common Language Runtime (CLR). Pointers are not supported by default in C# but unsafe keyword allows the use of the pointer variables.

However, extra care is required while handling unsafe code to prevent errors or security risks as pointers are complex and may lead to memory related errors such as stack overflow, overwritten system memory etc.

The following is an example:

using System;
namespace PointerDemo
{
  class Example
  {
     static unsafe void Main(string[] args)
     {
        char val = 'A';
        char* ptr = &val;
        Console.WriteLine("The character value is: {0} ", val);
        Console.WriteLine("Address of the value is: {0}", (int)ptr);
     }
  }
}

The output of the above program is as follows:

The character value is: A
Address of the value is: 220412608

The AssemblyQualifiedName property displays the qualified assembly name associated with a type. The program that demonstrates this property is as follows:

using System;  
using System.Reflection;  
public class Demo  
{  
   public static void Main()  
   {
        Type t = typeof(System.Object);
       Console.WriteLine ("Qualified assembly name:\n   {0}.", t.AssemblyQualifiedName.ToString());
   }
} 

The output of the above program is as follows:

Qualified assembly name:
System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.

Dictionary and Hashtable are Collections classes in C#. Hashtable class is a collection of key-and-value pairs organized based on the hash code of the key.

Dictionary is a collection of keys and values. Hashtable is slower than Dictionary. For strongly-typed collections, the Dictionary collection is faster and you prefer them.

Classes and methods in C# can be created using Generics that defer the specification of types until the class or method is declared. This means that the creation of classes and methods that work with any data type can be handled using Generics.

A Generic class can be defined using angle brackets <>. There are type parameters that are Generic. These can handle any data type that is specified in a Generics class. Also, a Generic method is a method that is declared by using type parameters.

A program that demonstrates generic class and generic method in C# is given as follows:

using System;
public class GenericClass<T>
{
   private T GenericMember;
   public GenericClass(T data)
   {
       GenericMember = data;
   }
   public T GenericMethod(T GenericParameter)
   {
       Console.WriteLine("The Generic parameter is: {0}",  GenericParameter);
       return GenericMember;
   }
   public T genericProperty { get; set; }
}
public class Program
{
public static void Main()
{
GenericClass<char> GenericObject1 = new GenericClass<char>('D');
GenericClass<int> GenericObject2 = new GenericClass<int>(70);
       char num1;
       int num2;
       Console.WriteLine("For a character variable");
       num1 = GenericObject1.GenericMethod('A');
       Console.WriteLine("The Generic member variable is: {0}",  num1);
       Console.WriteLine("For an integer variable");
       num2 = GenericObject2.GenericMethod(50);
       Console.WriteLine("The Generic member variable is: {0}",  num2);
}
}

The output of the above program is as follows:

For a character variable
The Generic parameter is: A
The Generic member variable is: D
For an integer variable
The Generic parameter is: 50
The Generic member variable is: 70

The equivalent of C++ friend keyword in C# is a nested class accessing the outer class private members. That would mean the inner class can access the outer class private members:

The using keyword in C# is used to specify the names of the namespaces that are used in the given program. For example - The System namespace is used in the programs with the keyword using.

A program that demonstrates the using keyword in C# is given as follows:

using System;
namespace Demo
{
   class Test
   {
     static void Main(string[] args)
     {
        int a, b, sum;
        a = 14;
        b = 2;
        sum = a + b;
        Console.WriteLine("The sum of {0} and {1} is {2}", a, b, sum);
     }
   }
}

The output of the above program is as follows:

The sum of 14 and 2 is 16

The Environment.Exit() method is used in C# to terminate this process. An exit code is returned by the method. For example, Environment.Exit(2) returns a value 2 showing that the file is in an incorrect format.

Be ready for one of the most frequently posed C# advanced interview questions.

Yes, we can create an array with non-default values. This can be achieved using Enumerable.Repeat in C#.

Details about System.Array.CopyTo() and System.Array.Clone() are given as follows:

System.Array.CopyTo()

This method copies all the elements that are in the current one-dimensional array into the one-dimensional array that is specified. The two parameters of the method are the array that is the destination array of the elements copied from the current array and the the index at which the array copying starts.

A program that demonstrates this is given as follows:

using System.IO;
using System;
class Demo
{
  public static void Main()
  {
     int[] source = new int[5] {6, 8, 1, 4, 7};
     int[] target = new int[5];
     source.CopyTo(target, 0);
     Console.WriteLine("The target array is: ");
     foreach (int i in target)
     {
         Console.WriteLine(i);
     }
  }
}

The output of the above program is given as follows:

The target array is:
6
8
1
4
7

System.Array.Clone()

This method creates a shallow copy of the array and returns it. Also, the  System.Array.Clone() method is slower than the System.Array.CopyTo() method.

A program that demonstrates this is given as follows:

using System.IO;
using System;
class Demo
{
  public static void Main()
  {
     int[] source = new int[5] {6, 8, 1, 4, 7};
     int[] target = new int[5];
     target = (int[])source.Clone();
     Console.WriteLine("The target array is: ");
     foreach (int i in target)
     {
         Console.WriteLine(i);
     }
  }
}

The output of the above program is given as follows:

The target array is:
6
8
1
4
7

Delegates is the C# equivalent to function pointers. However, unlike function pointers, the delegates encapsulate both an object instance and a method.

Delegates are fully object oriented and allow methods to be passed as parameters.

  • Abstract Class

An abstract class is a special kind of class that can be inherited but cannot be instantiated. For a class to be an abstract class, there should always be at least one abstract method should be present.

  • Interface

Interface is not a class, it is an entity that is defined by the work Interface. Like Abstract class we cannot create an instance of Interface. It has no implementation; only has the signature i.e. just the definition of the methods without the body.

Advantage of Interface is that it provides a way for a class to be a part of two classes: one from inheritance hierarchy and one from the interface.

Difference between Interface and Abstract Class

Feature
InterfaceAbstract class
Multiple inheritance
A class can inherit to multiple interfacesA class may inherit from only one abstract class.
Default implementationAn interface only have method declaration, no definition.An abstract class can have methods with complete definition or abstract methods that to be overriden in derived class
Access Modifiersfor interface everything is assumed as publicAn abstract class have access modifiers for the subs, functions, properties
HomogeneityInterfaces are better option when various implementations share the same method signature.Abstract classes are better when various implementations are of the same kind and use common behaviour or status.
Adding functionality (Versioning)Adding a new method to interface need to implemented in derived classeswhile adding new method we have the option of providing default implementation and therefore all the existing code might work properly.
Fields and ConstantsNo fields can be definedcan have fields and constants defined

Garbage collector manages allocation and reclaiming of memory. GC (Garbage collector) makes a trip to the heap and collects all objects that are no longer used by the application and then makes them free from memory.

Each time you create a new object, the common language runtime allocates memory for the object from the managed heap. As long as address space is available in the managed heap, the runtime continues to allocate space for new objects. However, memory is not infinite. Eventually the garbage collector must perform a collection in order to free some memory. The garbage collector's optimizing engine determines the best time to perform a collection, based upon the allocations being made. When the garbage collector performs a collection, it checks for objects in the managed heap that are no longer being used by the application and performs the necessary operations to reclaim their memory.

Garbage collection occurs when one of the following conditions is true:

  • The system has low physical memory. This is detected by either the low memory notification from the OS or low memory indicated by the host.
  • The memory that is used by allocated objects on the managed heap surpasses an acceptable threshold. This threshold is continuously adjusted as the process runs.
  • The GC.Collect method is called. In almost all cases, you do not have to call this method, because the garbage collector runs continuously. This method is primarily used for unique situations and testing.

Managed Heap

After the garbage collector is initialized by the CLR, it allocates a segment of memory to store and manage objects. This memory is called the managed heap, as opposed to a native heap in the operating system.

When the garbage collector is triggered, it reclaims the memory occupied by dead objects, also compacts the live objects so that they are moved together and dead space is removed. This way it makes the heap smaller and ensure that allocated objects stay together on managed heap. 

Based on object life heaps can be considered as accumulation of two heap: large object heap and small object heap.Heap is managed by different 'Generations', it stores and handles long-lived and short-lived objects, see the below generations of Heap:

  • 0 Generation (Zero): This generation holds short-lived objects, e.g., Temporary objects. GC initiates garbage collection process frequently in this generation.
  • 1 Generation (One): This generation is the buffer between short-lived and long-lived objects.
  • 2 Generation (Two): This generation holds long-lived objects like a static and global variable, that needs to be persisted for a certain amount of time. Objects which are not collected in generation Zero, are then moved to generation 1, such objects are known as survivors, similarly objects which are not collected in generation One, are then moved to generation 2 and from there onwards objects remain in the same generation.

What happens during a garbage collection

Following phases are there of garbage collection:

  • Marking Phase: that finds and creates a list of all live objects.
  • Relocating Phase: that updates the references to the objects that will be compacted.
  • Compacting Phase: that reclaims the space occupied by the dead objects and compacts the surviving objects. It moves objects that have survived a garbage collection toward the older end of the segment.

Func, Action and Predicate are define in C# 3.0 and these are generic inbuilt delegates.

  • Func Delegate

Func is generic delegate present in System namespace. It takes one or more input parameters and returns one out parameter. The last parameter is considered as a return value.

Func delegate type can include 0 to 16 input parameters of different types. It must have one return type. So return type is mandatory but input parameter is not.

Example1: Func delegate with two input parameters and one return value.

   Func func1 = DelegateClass.Add;  
   int value = func1(10, 20);  
   TParameter = 10,20;  
   TOutput = value = 30;  

Example 2: Func delegate with one input parameter and one return value.

   Func func2 = DelegateClass.GetValue;  
   int values = func2(30);  
   TParameter = 30  
   TOutput = 40;  

Example 3: Func delegate with zero input parameter and one return value.

   Func func3 = DelegateClass.GetResult;  
   intresultMulti = func3();  
   TParameter = Nothing  
   TOutput = 600;  
   Func with Anonymous methods:  
   Func func4= delegate(intx,int y){ return (x+y); };  
   int result = func4(2,3);  
   Func with Lambda expression:  
   Func func5= (intx,int y) => { return (x+y); };  
   int xx = func4(2,3);  
  • Action Delegate

Action is a generic delegate present in System namespace. It takes one or more input parameters and returns nothing.

So it does not return any value.

Example 1: Action delegate with two input parameters.

   Action action1=DelegateClass.ShowEmploye;  
   action1(30,"Rajesh");  
   TParameter = 30,Rajesh;  
   TOutput = Not available (No return value)  

Example 2: Action delegate with one input parameter.

   Action action2=DelegateClass.ShowMessage;  
   action2("Rajesh");  
   TParameter = “Rajesh”  
   TOutput = Not available  
Action delegate with Anonymous methods:
   Action action = delegate(String msg)  
   {
       Console.WriteLine(msg);  
   };
   action("rajesh");  
   Action delegate with Lambda expression: Action action = (msg) = & gt;  
   {
       Console.WriteLine(msg)  
   };
   action(“Rajesh”);  
  • Predicate Delegate

Predicate delegate is also inbuilt generic delegate and is present in System namespace.

It is used to verify certain criteria of method and returns output as Boolean, either True or False.

Predicate can be used with method, anonymous and lambda expression.

Example 1: Check String value is number using Predicate delegates.

Predicate predicate = DelegateClass.IsNumeric;
bool number = predicate("1234");

Example 2: Predicate delegate using Anonymous method.

   Predicate predicate = delegate(string str)  
   {
       double retNum;  
       bool isNum = Double.TryParse(Convert.ToString(str), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);  
       return isNum;  
   };
   bool found = predicate("12232");  

Example 3: Predicate delegate using lambda expression.

   Predicate predicate = (str) = & gt;  
   {
       double retNum;  
       bool isNum = Double.TryParse(Convert.ToString(str), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);  
       return isNum;  
   };
   bool found = predicate("12232");

Async-await is used to perform action asynchronously. It is required when there are long running activities, processing them synchronously may take long time and become blocker to web access. In an asynchronous process, the application can continue with other work that doesn't depend on the web resource until the potentially blocking task finishes.

The async and await keywords in C# are the heart of async programming. By using those two keywords, you can use resources in the .NET Framework. Asynchronous methods that you define by using the async keyword are referred to as async methods.

The following example shows an async method.

// Three things to note in the signature:  
//  - The method has an async modifier.   
//  - The return type is Task or Task<T>. (See "Return Types" section.)  
//    Here, it is Task<int> because the return statement returns an integer.  
//  - The method name ends in "Async."  
async Task<int> AccessTheWebAsync()  
{   
   // You need to add a reference to System.Net.Http to declare client.  
   HttpClient client = new HttpClient();  
   // GetStringAsync returns a Task<string>. That means that when you await the  
   // task you'll get a string (urlContents).  
   Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com");  
   // You can do work here that doesn't rely on the string from GetStringAsync.  
   DoIndependentWork();  
   // The await operator suspends AccessTheWebAsync.  
   // - AccessTheWebAsync can't continue until getStringTask is complete.  
   // - Meanwhile, control returns to the caller of AccessTheWebAsync.  
   // - Control resumes here when getStringTask is complete.   
   // - The await operator then retrieves the string result from getStringTask.  
   string urlContents = await getStringTask;  
   // The return statement specifies an integer result.  
   // Any methods that are awaiting AccessTheWebAsync retrieve the length value.  
   return urlContents.Length;  
}

For a method to be async, it should have following characteristics:

  • The method signature includes an async modifier.
  • The return type is one of the following types:
    • if method have a return statement then Task<TResult>.
    • if no return statement  then Task.
  • The method usually includes at least one await expression.

The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active.

An async method typically returns a Task or a Task<TResult>. Inside an async method, an await operator is applied to a task that's returned from a call to another async method. You specify Task<TResult> as the return type if the method contains a return statement that specifies an operand of type TResult.

You use Task as the return type if the method has no return statement or has a return statement that doesn't return an operand. An async method can't declare in, ref or out parameters, but the method can call methods that have such parameters. Similarly, an async method can't return a value by reference, although it can call methods with ref return values

A private constructor is a special instance constructor. It is generally used in classes that contain static members only. If a class has one or more private constructors and no public constructors, other classes (except nested classes) cannot create instances of this class. For example:

class NLog
{
   // Private Constructor:
   private NLog() { }
   public static double e = Math.E;  //2.71828...
}

The declaration of the empty constructor prevents the automatic generation of a default constructor.

Note that if you do not use an access modifier with the constructor it will still be private by default.

Private constructors are used to prevent creating instances of a class when there are no instance fields or methods, such as the Math class, or when a method is called to obtain an instance of a class.

There are two ways to use the using keyword in C#. One is as a directive and the other is as a statement.

1. Using Directive

Generally we use the using keyword to add namespaces in code-behind and class files. Then it makes available all the classes, interfaces and abstract classes and their methods and properties in the current page. Adding a namespace can be done in the following two ways:

  • To allow the normal use of types in a namespace:
    • using System.IO;  
    • using System.Text;  
  • To create an alias for a namespace or a type. This is called a using alias directive. 
    • using MyProject = TruckingApp.Services; 

2. Using Statement

This is another way to use the using keyword in C#. It plays a vital role in improving performance in Garbage Collection.

The using statement ensures that Dispose() is called even if an exception occurs when you are creating objects and calling methods, properties and so on. Dispose() is a method that is present in the IDisposable interface that helps to implement custom Garbage Collection. In other words if I am doing some database operation (Insert, Update, Delete) but somehow an exception occurs then here the using statement closes the connection automatically. No need to call the connection Close() method explicitly.

Another important factor is that it helps in Connection Pooling. Connection Pooling in .NET helps to eliminate the closing of a database connection multiple times. It sends the connection object to a pool for future use (next database call). The next time a database connection is called from your application the connection pool fetches the objects available in the pool. So it helps to improve the performance of the application. So when we use the using statement the controller sends the object to the connection pool automatically, there is no need to call the Close() and Dispose() methods explicitly

For Example:

   string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";  
   using (SqlConnection conn = new SqlConnection(connString))  
   {
         SqlCommand cmd = conn.CreateCommand();  
         cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";  
         conn.Open();  
         using (SqlDataReader dr = cmd.ExecuteReader())  
         {
            while (dr.Read())  
            Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1));  
         }
   }

In order to maintain security and type safety, C# does not support pointer generally. But by using unsafe keyword we can define an unsafe context in which pointer can be used. The unsafe code or unmanaged code is a code block that uses a pointer variable. In the CLR, unsafe code is referred to as unverifiable code. In C#, the unsafe code is not necessarily dangerous. The CLR does not verify its safety. The CLR will only execute the unsafe code if it is within a fully trusted assembly. If we use unsafe code, it is our own responsibility to ensure that the code does not introduce security risks or pointer errors.

Unsafe code cannot be executed in an un-trusted environment. For example, we cannot run unsafe code directly from the Internet

Some properties of unsafe codes are given bellow:

  • We can define Methods, types, and code blocks as unsafe
  • In some cases, unsafe code may increase the application’s performance by removing array bounds checks
  • Unsafe code is required in order to call native functions that require pointers
  • Using unsafe code brings security and stability risks
  • In order to compile unsafe code, the application must be compiled with /unsafe
  • Abstraction

Abstraction means to show only the necessary details to the client of the object. Abstraction is the process of refining away all the unneeded/unimportant attributes of an object and keep only the characteristics best suitable for your domain. Abstraction means putting all the variables and methods in a class which are necessary.

  • Encapsulation 

Encapsulation is a strategy used as part of abstraction. Encapsulation refers to the state of objects - objects encapsulate their state and hide it from the outside; outside users of the class interact with it through its methods, but cannot access the classes state directly. So the class abstracts away the implementation details related to its state. It is a method for protecting data from unwanted access or alteration. Encapsulation is the mechanism by which Abstraction is implemented.

Difference between Abstraction and Encapsulation

AbstractionEncapsulation
solves the problem in the design level.solves the problem in the implementation level.
hiding the unwanted data and giving only relevant data.hiding the code and data into a single unit to protect the data from outer world
set focus on the object instead of how it does ithiding the internal details or mechanics of how an object does something

When we want to transport an object through network then we need to convert the object into a stream of bytes. Serialization is a process to convert a complex objects into stream of bytes for storage (database, file, cache, etc) or transfer. Its main purpose is to save the state of an object.
De-serialization is the reverse process of creating an object from a stream of bytes to their original form.

Types of Serialization:

Serialization is of following types:

  • Binary Serialization
    In this process all the public, private, read only members are serialized and convert into stream of bytes. This is used when we want a complete conversion of our objects.
  • SOAP Serialization
    In this process only public members are converted into SOAP format. This is used in web services.
  • XML Serialization
    In this process only public members are converted into XML. This is a custom serialization. Required namespaces: System.Xml, System.Xml.Serialization.

Serialization is used in the following purposes:

  • To pass an object from on application to another
  • In SOAP based web services
  • To transfer data through cross platforms, cross devices

Early Binding

The name itself describes that compiler knows about what kind of object it is, what are all the methods and properties it contains. As soon as you declared the object, .NET Intellisense will populate its methods and properties on click of the dot button

Common Examples:

  • ComboBox cboItems;
  • ListBox lstItems;

In the above examples, if we type the cboItem and place a dot followed by, it will automatically populate all the methods, events and properties of a combo box, because compiler already know it's an combobox.

Late Binding
The name itself describes that compiler does not know what kind of object it is, what are all the methods and properties it contains. You have to declare it as an object, later you need get the type of the object, methods that are stored in it. Everything will be known at the run time.

Common Examples:

  • Object objItems;
  • objItems = CreateObject("DLL or Assembly name");

Here during the compile time, type of objItems is not determined. We are creating an object of a dll and assigning it to the objItems, so everything is determined at the run time.

Composition

Like Inheritance gives us an 'is-a' relationship. Composition gives us a 'part-of' relationship. Composition is shown on a UML diagram.

Composition

If we were going to model a car, it would make sense to say that an engine is part-of a car. Within composition, the lifetime of the part (Engine) is managed by the whole (Car), in other words, when Car is destroyed, Engine is destroyed along with it.

public class Engine
{
 . . .
}
public class Car
{
   Engine e = new Engine();
   .......
}

As you can see in the example code above, Car manages the lifetime of Engine.

Aggregation

As Inheritance gives us 'is-a' and Composition gives us 'part-of', Aggregation gives us a 'has-a' relationship. Within aggregation, the lifetime of the part is not managed by the whole.

For Example:

Aggregation

Aggregation would make sense in this situation, as a Person 'has-a' Address. It wouldn't make sense to say that an Address is 'part-of' the Person, because it isn't. Consider it this way, if the person ceases to exist, does the address

So how do we express the concept of aggregation in C#? Well, it's a little different to composition. Consider the following code:

public class Address
{
 . . .
}
public class Person
{
    private Address address;
    public Person(Address address)
    {
        this.address = address;
    }
    . . .
}

Person would then be used as follows:

Address address = new Address();
Person person = new Person(address);

or

Person person = new Person( new Address() );

Here  Person does not manage the lifetime of Address. If Person is destroyed, the Address still exists.


dynamic is a new static type that acts like a placeholder for a type not known until runtime. Once the dynamic object is declared, it is possible to call operations, get and set properties on it, even pass the dynamic instance pretty much as if it were any normal type.

The dynamic type enables the operations in which it occurs to bypass compile-time type checking. these operations are resolved at run time. Type dynamic behaves like type object in most circumstances. However, operations that contain expressions of type dynamic are not resolved or type checked by the compiler.

As part of the process, variables of type dynamic are compiled into variables of type object. Therefore, type dynamic exists only at compile time, not at run time.

The following example contrasts a variable of type dynamic to a variable of type object. To verify the type of each variable at compile time, place the mouse pointer over dyn or obj in the WriteLine statements. IntelliSense shows dynamic for dyn and object for obj.

class Program
{
   static void Main(string[] args)
   {
       dynamic dyn = 1;
       object obj = 1;
       // Rest the mouse pointer over dyn and obj to see their
       // types at compile time.
       System.Console.WriteLine(dyn.GetType());
       System.Console.WriteLine(obj.GetType());
   }
}

Limitations of dynamic

  •  Extension methods cannot be called
  •  Anonymous functions (lambdas) cannot be called
  •  Because of the above, LINQ support is limited

Generics are the most powerful features introduced in C# 2.0. It is a type-safe data structure that allows us to write codes that works for any data types.

For example, by using a generic type parameter T you can write a single class that other client code can use without incurring the cost or risk of runtime casts or boxing operations

// Declare the generic class.
public class GenericList<T>
{
   public void Add(T input) { }
}
class TestGenericList
{
   private class ExampleClass { }
   static void Main()
   {
       // Declare a list of type int.
       GenericList<int> list1 = new GenericList<int>();
       list1.Add(1);
       // Declare a list of type string.
       GenericList<string> list2 = new GenericList<string>();
       list2.Add("");
       // Declare a list of type ExampleClass.
       GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
       list3.Add(new ExampleClass());
   }
}

Stack

  • Stack is an array of memory.
  • It is a Last-in, First-out (LIFO) data structure.
  • Data can be added to and deleted only from the top of the stack.
  • Placing a data item at the top of the stack is called pushing the item onto the stack.
  • Deleting an item from the top of the stack is called popping the item from the stack.

Heap

The heap is an area of memory where chunks are allocated to store certain kinds of data objects. Unlike the stack, data can be stored and removed from the heap in any order. CLR’s garbage collector (GC) automatically cleans up orphaned heap objects when it determines that your code can no longer access them.

Difference between Stack and Heap Memory

Stack MemoryHeap Memory
Static memory allocationDynamic memory allocation
Variables allocated on stack are directly stored to memoryVariables allocated on Heap have their memory allocated at runtime
Variables cannot be re-sizedVariables can be re-sized
Very fast accessRelatively slow access
Variables stored on stack are visible only to the owner threadObjects created on the heap are visible to all threads.
Stack is always reserved in LIFO order, the most recently reserved block is always the next block to be freed.You can allocate a block and free it at any time.
The  moment stack space is exhausted, .NET runtime throws StackOverflowException.Memory.NET runtime creates special thread that monitors allocation of heap space called Garbage Collector

Covariance and Contravariance enable implicit reference conversion for array types, delegate types, and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.

The following code demonstrates the difference between assignment compatibility, covariance, and contravariance.

// Assignment compatibility.    string str = "test";   // An object of a more derived type is assigned to an object of a less derived type.    object obj = str;  
// Covariance.    IEnumerable<string> strings = new List<string>();   // An object that is instantiated with a more derived type argument    // is assigned to an object instantiated with a less derived type argument.    // Assignment compatibility is preserved.    IEnumerable<object> objects = strings;  
// Contravariance.             
// Assume that the following method is in the class:    // static void SetObject(object o) { }    Action<object> actObject = SetObject;   // An object that is instantiated with a less derived type argument    // is assigned to an object instantiated with a more derived type argument.    // Assignment compatibility is reversed.    Action<string> actString = actObject;

Covariance and contravariance support for method groups allows for matching method signatures with delegate types. This enables you to assign to delegates not only methods that have matching signatures, but also methods that return more derived types (covariance) or that accept parameters that have less derived types (contravariance) than that specified by the delegate type.

The following code example shows covariance and contravariance support for method groups.

static object GetObject() { return null; }   static void SetObject(object obj) { }   static string GetString() { return ""; }   static void SetString(string str) { }   static void Test()   {      // Covariance. A delegate specifies a return type as object,      // but you can assign a method that returns a string.      Func<object> del = GetString;      // Contravariance. A delegate specifies a parameter type as string,      // but you can assign a method that takes an object.      Action<string> del2 = SetObject;   }

In .NET Framework 4 or newer C# supports covariance and contravariance in generic interfaces and delegates and allows for implicit conversion of generic type parameters

The following code example shows implicit reference conversion for generic interfaces.

IEnumerable<String> strings = new List<String>();   
IEnumerable<Object> objects = strings;

Description

C# is a widely used programming language in the IT industry. Microsoft develops it, and it is mostly used for building desktop applications. More recently, C# has been used in developing Windows 8/10 applications.

Based on the survey conducted by Stackoverflow, C# is known as the 4th most popular programming language, with 31% of the developers using it regularly. Since its demand is rising in the market, it is necessary today to have a strong understanding of this language to land any dream job in the software industry.

If you are looking to make your career in the software industry as a developer, these best interview questions in C sharp will be useful in cracking the interview. To learn more about C-Sharp Courses, enroll in our course and strengthen your fundamental core. Below is a list of the most asked C# interview questions and answers. These C# interview questions can be useful for freshers and experienced professionals to clear the interview. To make you industry ready with more knowledge of programming, join our programming training course and prepare yourself confidently for the interview.

Read More
Levels