Q1 What is the difference between ref
and out
parameters?
Answer: Both pass arguments by reference, but ref
requires variables to be initialized before passing while out
doesn’t. With out
, the method must assign a value before returning. ref
is for bidirectional parameter passing, while out
is for returning multiple values from a method.
static void Main()
{
// ref example - variable must be initialized
int x = 10;
DoubleRef(ref x);
Console.WriteLine(x); // Output: 20
// out example - variable doesn't need initialization
int y;
SetToFive(out y);
Console.WriteLine(y); // Output: 5
}
Q2. What is the difference between const
and readonly
?
Answer: const
values are determined at compile time and cannot be changed. They are implicitly static and must be primitive types or string. readonly
fields can be initialized at runtime in the constructor and can be instance members. readonly
variables can be of any type and are evaluated at runtime.
class Program
{
// const: Compile-time constant, implicitly static
public const int ConstValue = 100;
// readonly: Run-time constant, can be instance member
public readonly int ReadOnlyValue = 200;
// readonly can be assigned in constructor
public Program(int value)
{
ReadOnlyValue = value; // Valid
// ConstValue = value; // Error! Cannot assign to const
}
}
Q3. Explain the access modifiers in C# and their scopes.
public
: Accessible from anywhere (any class , from other assembly)private
: Accessible only within the containing type(class).protected
: Accessible within the containing type and any derived types.internal
: Accessible within the same assemblyinternal: Accessible within the same assembly
OR derived types (remember it is OR and not ‘and’)
Q4. What is the difference between value types and reference types?
Answer: Value types (integer,structs, enums) are stored on the stack, passed by value (copying), and compared by value.
Reference types (classes, interfaces, delegates) are stored on the heap with a reference on the stack, passed by reference, and compared by reference.
Value types are better for small, immutable data structures, while reference types are better for larger objects, polymorphism, and when identity matters.
Q5.What is the difference between StringBuilder
and string ?
Answer: Strings in .NET are immutable (something that can’t be changed), so each string concatenation creates a new string object, leading to multiple objects being created (1 per concatenation) leading to potential performance issues.
StringBuilder
allows strings to be concatenated or modified without creating new objects. When performing multiple string operations, StringBuilder
is much more efficient. However, for simple concatenations (2-3 strings) you can normally use string concatenation i.e. like(string c= a+b) but for multiple concatenations you should use StringBuilder.
Q6. Explain the SOLID principles in the context of C#.
- Single Responsibility: Classes should have only one reason to change. Use small, focused classes rather than monolithic ones.
- Open/Closed: Classes should be open for extension but closed for modification. Use inheritance, interfaces, and composition.
- Liskov Substitution: Derived classes must be substitutable for their base classes. Ensure overrides maintain contract semantics.
- Interface Segregation: Clients shouldn’t depend on interfaces they don’t use. Create small, cohesive interfaces.
- Dependency Inversion: High-level modules shouldn’t depend on low-level modules. Both should depend on abstractions. Use DI containers and interfaces.
Q7. What is boxing and unboxing, and why should it be avoided?
Answer: Boxing is the process of converting a value type to a reference type by wrapping it in an object. Unboxing extracts the value type from the object. This causes performance issues because it creates heap allocations, increases garbage collection pressure, and requires runtime type checks. Modern C# largely avoids this with generics.
static void Main()
{
// Value type
int number = 42;
// Boxing: Converting value type to reference type (object)
object boxed = number;
// Unboxing: Converting back from reference type to value type
int unboxed = (int)boxed;
}
Q8.What is the difference between “==” and Equals() method?
“==” compares references for reference types, while Equals() compares the content. For value types, they both compare values unless overridden. For example in below example even if p1 and p2 are different instances but if we override Equals to compare just Id (assuming if Id is same , employees are same) it will return true value.
Employee p1 = new Employee { Name = "Alice", Id = 1 };
Employee p2 = new Employee { Name = "Alice", Id= 1};
Employee p3 = p1;
Console.WriteLine($"{p1 == p2}");// False - different references
Console.WriteLine($"{p1 == p3}"); // True - same reference
Console.WriteLine($"{p1.Equals(p2)}");// True- We have overriden the Equals method to compare only their Id . Refer the overridden method below.
Console.WriteLine($"p1.Equals(p3): {p1.Equals(p3)}"); // True - same reference
public class Employee {
public override bool Equals(object obj)
{
Employee other = (Employee)obj;
return Id == other.Id;
}
}
Q9. What is the difference between “throw” and “throw ex”?
“throw” re-throws the original exception, keeping the original stack trace. It is better to use just “throw;” as it will store the stack trace. What is stack trace? Stack Trace is used to store all the method calls that were called in one execution. It stores any exception that happens with the line number.
Imagine if error happened on line 4, but in catch block if write throw ex, it will create new exception and when you read or log exception it will tell that issue happened at line 8 instead of line 4.
try //line 1
{ //line 2
Person p=null; //line 3
p.GetFullName();//line 4 . exception happens here
}
catch // line 6
{
throw ex;// line 8
}
Also, image what will happen if Method A threw exception and Method B which called Method A receives the exception object and does throw ex, it will appear that exception happened at Method B instead of Method A.
Q10. What is a Static Constructor?
What types of Access modifier Static Constructor can have?
Can static constructor have any parameters?
How many static constructors can a class have?
A static constructor in C# is a special constructor that is used to initialize static members of a class or perform actions that need to be done only once for the class—not per object.
Some of its key characteristics are:
- It can’t have any access modifiers like public, private etc.
- You can’t pass arguments to a static constructor.
- Automatically invoked once per type, when any static member is accessed.
- Used to initialize static fields or perform setup logic that applies to the class as a whole.
- A class can have only one static constructor
Q11. What is the difference between FirstOrDefault and SingleOrDefault in C#?
FirstOrDefault() returns the first element that matches the predicate(condition), while SingleOrDefault() throws an exception if more than one element matches the predicate.
If there are no matches, both methods return the default value for the type.
List<int> numbers = new List<int> { 1, 2, 3, 3, 4 };
var first = numbers.FirstOrDefault(n => n == 3); // ✅ Returns first 3
Console.WriteLine($"FirstOrDefault: {first}"); // Output: 3
try
{
var single = numbers.SingleOrDefault(n => n == 3); // ❌ Throws exception
Console.WriteLine($"SingleOrDefault: {single}");
}
Q12.What Are Generics? What are some benefits of using Generics.
Generics in C# allow you to define type-safe classes, interfaces, methods, and delegates without committing to specific data types. When you use generics, you define a blueprint that can work with any data type.
public class GenericList<T>
{
private T[] items;
public void Add(T item)
{
// Add logic here
}
}
Some advantages of using Generics are
- Type Safety: Generics detect type errors at compile-time rather than runtime, reducing bugs and runtime exceptions.
- Code Reusability: Write a class or method once that can work with different types without duplication.
- Performance: Generics avoid boxing and unboxing operations, which improves performance, especially with value types.
- Cleaner Code: Eliminates the need for type casting and type checking, making code more readable and maintainable.
- Specialized Functionality: You can add constraints to generics to ensure they work only with types that have specific capabilities.
Q13. What are generic constraints in C#? Give examples of common constraints.
Generic constraints restrict the types that can be used as arguments for type parameters in generic classes, interfaces, methods, or delegates.
They ensure that the type you’re working with has certain capabilities, like having a parameterless constructor, being a class, or implementing a specific interface.
public class MyClass<T> where T : IDisposable
{
public void Close(T item)
{
item.Dispose(); // ✅ We know T implements IDisposable
}
}
example of constraints
where T : class T
where T : struct
where T : new()
where T : Interface
Q14. What is the use of the “using” block in C#?
In .NET, the using
block is used to dispose(by calling Dispose method) the object automatically once it comes out of scope of the Dispose.
It works only for the classes that implement the IDisposable
interface . The classes that implement IDisposable are those classes that hold unmanaged resources like file handles, database connections, network streams, etc.
When an object is created inside a using block, the C# compiler automatically generates code to ensure that the object’s Dispose method is called when the block is exited. When you use “using” block, the compiler internally wraps the code with Try and Finally , inside finaly it calls the dispose method automatically ensuring that the Dispose is always called even if there is any exception.
By ensuring that objects are properly disposed of, the using block helps prevent resource leaks and other problems that can arise from not cleaning up after objects that use
unmanaged resources.

If you are writing any class which deals with unmanaged resources ,it is preferred to implement IDisposable interface. Inside the Dispose method, you should clear the unmanaged resources. Also, it is advisable to also create a destructor(Finalize method) which would call the Dispose method if the user forgets to call it explicitly to prevent memory leak due to unmanaged resources.
Q16.What is Dependency Injection, and what are the different types?
Answer: Dependency Injection is a technique where objects receive their dependencies from an external source rather than creating them. Types:
- Constructor Injection: Dependencies provided via constructor (most common, makes dependencies explicit)
- Property Injection: Dependencies set through public properties (useful for optional dependencies)
- Method Injection: Dependencies provided as method parameters (when dependencies vary by method)
DI frameworks like Microsoft.Extensions.DependencyInjection manage the object graph and lifetime of dependencies. This library is present by default in .Net Core and .Net 6+ applications.
Q17. Have you worked on any Object Relational Mapper (ORM) tools. Or Have you worked on Entity Framework?
Entity Framework (EF) is an Object-Relational Mapper (ORM) for .NET provided by Microsoft. It enables developers to work with databases using .NET objects (normal C# classes) . It helps developer focus more on business logic than writing SQL scripts etc. Internally EF changes the LINQ To EF queries in to SQL scripts.
Other third part but useful tools that can be used instead of EF are : Dapper , NHibernate.
Q18. What are the main approaches to use EF?
Model-First – Use a visual designer to create models and generate both code and database schema.
Code-First – Define your models in C# code; EF creates the DB schema.
Database-First – Reverse-engineer a model from an existing DB.
Generally it is preferred to use Code First in the new project ,if you are starting from scratch or working on Microservices Architecture where each Service has one database.
In Production , normally database will be created separately using Deployment pipeline , you can use a Pipeline task to generate the SQL script from the EF migrations which helps to generate script from models. (More on this in Level 3)
Q19. What is DbContext in Entity Framework?
DbContext
is the primary class in EF that manages database connections and provides access to data via DbSet<TEntity>
. It handles querying, saving data, tracking changes, and more.
Think of DbContext
as a gateway between your C# code and your SQL database. It helps to map table to the EF model and to translate linq queries to the SQL commands
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
// DbSet represents tables in the database
public DbSet<Employee> Employees { get; set; }
public DbSet<Department> Departments { get; set; }
}
Q20. Use Linq query to find the department with the highest average salary?
Assuming you have List of Employees (employees) which has Department and Salary properties.
Note: The below example is for in memory operations (Linq to Objects) not EF. You can chanage it to EF by using something like dbContext.Employees instead of employees.
USING Method Syntax
-------------------
var topDepartment = employees
.GroupBy(e => e.Department)
.Select(g => new {
Department = g.Key,
AvgSalary = g.Average(e => e.Salary)
})
.OrderByDescending(g => g.AvgSalary)
.FirstOrDefault();
USING QUERY SYNTAX
-------------------
var topDepartment =
(from e in employees
group e by e.Department into deptGroup
let avgSalary = deptGroup.Average(emp => emp.Salary)
orderby avgSalary descending
select new
{
Department = deptGroup.Key,
AvgSalary = avgSalary
}).FirstOrDefault();
For your reference, if above was Linq to EF, the sql query will be
SELECT Department, AVG(Salary) AS AvgSalary
FROM Employees
GROUP BY Department
ORDER BY AvgSalary DESC
LIMIT 1;
Q21. Explain the concept of unit testing in C# and the common frameworks.
Answer: Unit testing verifies individual components in isolation. For C#, common frameworks include:
- xUnit: Modern, extensible framework favoring composition over inheritance, using attributes like
[Fact]
and[Theory]
- NUnit: Feature-rich framework with extensive attributes and constraints
- MSTest: Microsoft’s framework integrated with Visual Studio
Q22. Have you used any mocking framework. Why do we need to Mock while writing unit test?
Moq is a popular .NET library that helps you create mock objects for unit tests. We use Mocking to mock the dependencies(or other class’s method call) so that we don’t test that.
Suppose we are testing ClassA which has Method A. Assume ClassA calls Class B which has MethodB having database calls. We would mock ClassB and it’s MethodB. so that we don’t hit the database. We would mock MethodB and return the value which we expect from database in this example. Our focus is to test MethodA and not Database calls.
Q23. Can we mock any class using Moq?
In Moq, you can mock interfaces and virtual or abstract methods of classes, but you cannot mock non-virtual methods of regular concrete classes directly.
To mock IRepository interface’s GetById method, first we need to wrap IRepository with Mock object and then call it’s setup method to returns the value we want using its Mock’s Returns method.
var mockRepo = new Mock<IRepository>();
mockRepo.Setup(r => r.GetById(It.IsAny<int>())).Returns(new Item { Id = 1 });
Q24.Explain the difference between Task
and Thread
in C#.
Task is a higher-level abstraction built on top of the Thread Pool. It Represent asynchronous operations that may or may not use threads.It is part of the Task Parallel Library (TPL) introduced in .NET Framework 4.0. It is used in asynchronous programming with async/await pattern. It support return of values using Task<T>. It is useful for I/O bound operation.
A thread in C# is a low-level execution path within a program that enables concurrent processing. It represents an actual operating system thread that can execute code independently. It is useful for CPU bound operation.
//Thread Example. Thread is created by creating instance of Thread class.
static void Main()
{
// Create and start a new thread
Thread workerThread = new Thread(DoWork);
workerThread.Start("Hello from thread");
}
static void DoWork(object message)
{
Console.WriteLine($"Message: {Hello, I am called by Thread}");
}
//Task Example
Task object can be created by using Task.Run(), Task.Factory.StartNew()
Task<string> task = Task.Run(() =>
{
Thread.Sleep(2000);
return "Task completed successfully";
});
Q25. What is the difference between Inversion of Control and Dependency Injection?
Answer: Inversion of Control (IoC) is a broader principle where the control flow is inverted—instead of your code calling a framework, the framework calls your code.
Dependency Injection (DI) is a specific technique that implements IoC by having dependencies provided to objects rather than objects creating their dependencies. IoC is the general principle, while DI is a specific implementation pattern.
Q26. Have you worked on Extension method? Provide steps to create it.
Extension methods allow you to “add” methods to existing types without modifying the original type. They’re particularly useful for extending classes that you can’t modify directly (like those in the .NET Framework or if we want to add method to any class which we are referring from third party libraries or references we don’t have access to.
Steps:
- Define a static class.
- First parameter must use the
this
keyword followed by the type being extended and parameters, if any.
// Static class to contain extension methods
public static class StringExtensions
{
// Extension method for string class
// The "this" keyword before the parameter type indicates it's an extension method
public static int WordCount(this string str)
{
if (string.IsNullOrWhiteSpace(str))
return 0;
return str.Split(new[] { ' ', '.', '?', '!' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
More questions to be added every week.