Interview Questions

10 most frequently asked technical questions in C# Interviews

C# Interview FAQs: Most Common Technical Questions Answered

Abnoan Muniz
.Net Programming

--

C# | most frequently asked technical questions | technical questions | interview Questions | technical questions C#

As a C# developer, you’re probably no stranger to the feeling of nerves before an interview. But don’t worry. We’ve got you covered. In this post, we’ll discuss the 10 most frequently asked technical questions in C# interviews and show you how to answer them.

1: “How do you implement exceptions?”

Well, my friends, exception handling is a concept in programming that allows you to handle and respond to unexpected errors in your code. In C#, exception handling is done using the try, catch, and finally keywords.

try
{
// Code that may throw an exception
int x = 0;
int y = 10 / x;
}
catch (DivideByZeroException ex)
{
// Code to handle the exception
Console.WriteLine("Cannot divide by zero.");
}
finally
{
// Code that will always execute
Console.WriteLine("Exception handling complete.");
}

In the example above, we have a try block that contains the code that may throw a DivideByZeroException, a catch block that includes the code that will handle the exception and print an error message, and a finally block that includes the code that will consistently execute and print a message indicating that the exception handling is complete.

It’s also important to note that you should only throw exceptions for exceptional cases, not for expected errors. For example, returning a specific error message is better than throwing an exception if a user inputs an invalid password.

2: What is the difference between const and read-only variables?

A const is a variable whose value is known at compile-time and cannot be changed at runtime. It must be initialized when declared, and it cannot be changed once it is set. For example:

const int x = 10;
x = 20; // Error: A constant value must be a compile-time constant

On the other hand, a readonly is a variable whose value can be set only during initialization or in a constructor. It can be changed at runtime. For example:

public class MyClass
{
//during initialization
public readonly int x = 5;
public readonly int y;

public MyClass(int someValue)
{
//initialization in a constructor
y = someValue;
}

public void MyMethod()
{
// Attempting to assign a new value to a readonly variable
// will result in a compile-time error
y = 20; // Error: The left-hand side of an assignment must be a variable, property or indexer
}
}

One key difference between const and readonly is that const variables must be initialized with a value that can be computed at compile-time, whereas readonly can be initialized with a value that is calculated at runtime.

Another difference is that the const value is embedded directly into the IL code that uses it, whereas the value of a readonly is stored separately in memory and accessed at runtime.

Both const and readonly are used to create variables whose values cannot be modified after initialization, but they are used in different scenarios and have other characteristics.

3: What is the difference between an interface and an abstract class?

An interface is a contract defining a set of methods and properties a class must implement. An interface cannot contain implementation details and describes specific behavior that a class must have. For example:

public interface IShape
{
int GetArea();
}

On the other hand, an abstract class partially implements a class and can contain both abstract and non-abstract members. And can define a standard implementation for its derived classes to inherit and use, but a class can inherit from only one abstract class. For example:

public abstract class Shape
{
public int Width { get; set; }
public int Height { get; set; }

public void DisplayDimensions()
{
Console.WriteLine("Width: " + Width + ", Height: " + Height);
}

public abstract double GetArea();
}

public class Rectangle : Shape
{
public override double GetArea()
{
return Width * Height;
}
}

In this example, the Shape is an abstract class that defines the properties Width and Height. It also has a non-abstract method called DisplayDimensions() which simply displays the values of the Width Height properties.

The Shape also has an abstract method called GetArea() which does not have an implementation. The GetArea() is declared abstract because the formula to calculate the area of a shape will be different for different types of shapes (e.g., rectangle, circle, etc.). Therefore, it is left for the derived classes to provide an implementation.

The Rectangle class is a derived class of Shape . It provides an implementation for the GetArea() method using a formula Width * Height specific to rectangles.

You can’t create an instance of an abstract class, but you can make an instance of the derived class Rectangle and call its methods.

Rectangle rectangle = new Rectangle(){Width = 2, Height = 3};
rectangle.DisplayDimensions(); // Width: 2, Height: 3
Console.WriteLine(rectangle.GetArea()); // 6

You can see that the Rectangle inherits the properties and the non-abstract method from the Shape class, but it provides its implementation for the abstract method GetArea().

Back to the differences

One key difference between interfaces and abstract classes is that a class can implement multiple interfaces but inherit from only one abstract class.

Another difference is that interfaces define behavior contracts, whereas abstract classes can define behavior and implementation.

In conclusion, interfaces mainly define a contract for behavior that multiple unrelated classes can implement. In contrast, abstract classes provide a standard implementation for a hierarchy of related classes and can contain non-abstract members.

4: What is the difference between a queue and a stack?

A queue data structure follows the First-In-First-Out (FIFO) principle. Elements are added to the end of the queue and removed from the front. For example:

Queue<int> myQueue = new Queue<int>();
myQueue.Enqueue(10); // Add 10 to the end of the queue
myQueue.Enqueue(20); // Add 20 to the end of the queue
int x = myQueue.Dequeue(); // Remove and return the first element (10)

On the other hand, a stack is a data structure that follows the Last-In-First-Out (LIFO) principle. Elements are added to the top of the stack and removed from the top. For example:

Stack<int> myStack = new Stack<int>();
myStack.Push(10); // Add 10 to the top of the stack
myStack.Push(20); // Add 20 to the top of the stack
int x = myStack.Pop(); // Remove and return the top element (20)

One key difference between queues and stacks is how elements are added and removed. Queues follow the FIFO principle, and stacks follow the LIFO principle.

Another difference is that queues typically have Enqueue and Dequeue, while stacks typically have methods such as Push and Pop.

5: What is the difference between value and reference types?

A value type is a type that holds the data within its memory allocation. Value types include primitive types, such as int, float, char, bool, double and structs and enumerations. For example:

int x = 10;
float y = 10.5f;
char z = 'a';
bool isTrue = true;
double d = 15.6;

On the other hand, a reference type is a type that holds a reference to the memory location where the data is stored. Reference types include classes, interfaces, string and arrays. For example:

public class MyClass
{
public int x;
}
MyClass obj = new MyClass();
obj.x = 10;
string myString = "Hello, World!";

One key difference between value types and reference types is that value types are stored on the stack, and reference types are stored on the heap. This means that when a value type is passed as a parameter to a method, a copy of the value is passed, whereas when a reference type is passed as a parameter, a reference to the memory location is passed.

Another difference is that value types have a default value, whereas reference types have a default value of null.

Boxing and unboxing

It is a conversion technique used in C# to convert a value type to a reference type and vice-versa. Boxing converts a value type to a reference type, while unboxing converts a reference type back to a value type. The process of boxing involves creating an instance of the System.Object and storing the value type in this instance. The process of unboxing consists in extracting the value type from the instance of the System.Object.

For example, consider the following code:

int x = 10;
object obj = x; // This is boxing
int y = (int) obj; // This is unboxing

In the above example, x is a value type and obj a reference type. The value x is boxed into an object and assigned to obj. Then the value obj is unboxed and assigned to y.

6: What’s the difference between the protected and private access modifiers?

In C#, access modifiers are used to control the accessibility of class members, such as fields, properties, and methods. There are four access modifiers: public, private, protected, and internal.

The private access modifier means that the class member can only be accessed within the same class. For example:

public class MyClass
{
private int x;
private void MyMethod()
{
x = 10; // This is valid
}
}

On the other hand, the protected access modifier means that the class member can be accessed within the same class or by derived classes. For example:

public class MyBaseClass
{
protected int x;
}
public class MyDerivedClass : MyBaseClass
{
public void MyMethod()
{
x = 10; // This is valid
}
}

One key difference between protectedand privateaccess modifiers are that protectedmembers can be accessed by derived classes, while private members can’t.

Another difference is that protectedmembers can be accessed from within the class in which they are declared or from any class derived from that class whileprivatemembers can only be accessed from within the class in which they are declared.

7: How do you implement asynchronous programming?

Asynchronous programming is becoming increasingly important in the world of C# development. With the rise of multi-core processors and the need to improve the responsiveness of applications, asynchronous programming is more important than ever.

In C#, asynchronous programming can be implemented using the async and await keywords. These keywords allow you to write asynchronous code that looks and behaves like synchronous code.

For example, let’s say we have a method that performs a long-running task, such as downloading a file from the internet. Without asynchronous programming, this method would block the execution of the program until the task is complete.

private void DownloadFile()
{
// Perform a long-running task
// ...
}

With asynchronous programming, we can use the async to indicate that the method will be asynchronous and that the await to suggest that the program should wait for the task to be complete before continuing.

private async void DownloadFile()
{
// Perform a long-running task
await Task.Run(() => {
// long-running task
});
}

Using asyncand awaitallows us to perform long-running tasks without blocking the execution of the program, improving the responsiveness of our applications.

8: How do you implement threading?

Threading allows you to run multiple tasks simultaneously, improving the performance and responsiveness of your applications.

In C#, there are several ways to implement threading, but the most common approach is to use the Thread from the System.Threading namespace.

The Thread allows you to create and start a new thread, and it provides several methods for controlling the execution of the thread, such as Start(), Join() and Abort().

For example, let’s say you have a method that generates many random numbers. Without threading, this method would block the execution of the program until the task is complete.

private void GenerateRandomNumbers()
{
List<int> numbers = new List<int>();
Random random = new Random();
for (int i = 0; i < 1000000; i++)
{
numbers.Add(random.Next());
}
}

With threading, we can create a new thread to perform the task simultaneously with the main thread. This allows the program to continue executing other tasks while the new thread handles the long-running task in the background. This significantly improves the performance and responsiveness of the application, as the main thread is not blocked and can continue processing other tasks.

private void GenerateRandomNumbers()
{
Thread thread = new Thread(() => {
List<int> numbers = new List<int>();
Random random = new Random();
for (int i = 0; i < 1000000; i++)
{
numbers.Add(random.Next());
}
});
thread.Start();
}

9: How do you implement a generic method?

Generics in C# allows you to write code that can work with any type instead of being tied to a specific type. This means you can write a single method or class that can work with multiple types without writing separate methods for each type.

A generic method is a method that is declared with a type parameter, which is represented by a placeholder for the actual type that will be used when the method is called.

For example, let’s say you want to write a method that compares two values of the same type and returns the more significant value. Without generics, you would have to write separate methods for each type, such as CompareInts(), CompareFloats(), and so on.

With generics, you can write a single CompareValues<T>() method that can work with any type.

public static T CompareValues<T>(T value1, T value2) where T : IComparable<T>
{
return value1.CompareTo(value2) > 0 ? value1 : value2;
}

You can use this method to compare values of any kind that implements the IComparable<T>.

int largerInt = CompareValues(5, 10);
string largerString = CompareValues("apple", "banana");

It’s important to note that when using generics, it’s an excellent practice to constrain the type parameter to specific interfaces or base classes to ensure that the methods used by the generic method are available.

10: What is LINQ, and how do you use it?

LINQ, or Language-Integrated Query, is a set of features introduced in C# 3.0 that allows you to query and manipulate data in various data sources, including arrays, lists, and databases, using a consistent and expressive syntax.

LINQ is built on top of the .NET framework and integrated into C# and Visual Basic, meaning you can write LINQ queries directly in your code using the same language and syntax as your other code.

The main advantage of using LINQ is that it allows you to write expressive and readable code that you can use to filter, sort, and transform data without having to write complex loops and conditional statements.

For example, let’s say you have a list of customers and you want to find all customers whose name starts with “A”:

List<Customer> customers = GetCustomers();

var query = from c in customers
where c.Name.StartsWith("A")
select c;

This query uses the from to define the data source, the where to filter the data and the select to project the data.

LINQ also supports method-based syntax, and you can use the same query as above like this:

var query = customers.Where(c => c.Name.StartsWith("A"));

In addition to querying data, LINQ also provides methods for manipulating data, such as OrderBy, GroupBy, Select, and Join among others.

Thanks for reading! Before you go:

If you find this article helpful, please consider giving claps and following me. 👏👉

Take advantage of my other stories! 👇🔽

Disclosure: A small part of this article has been written with the assistance of AI, and the writer carefully reviews all the content.

--

--

Abnoan Muniz
.Net Programming

Senior .NET Developer, Passionate about problem-solving. Support me: https://ko-fi.com/abnoanmuniz, Get in touch: linktr.ee/AbnoanM