C Sharp [C#] interview questions are your golden ticket to demonstrating proficiency, depth of knowledge, and passion for software development in interviews.
Love C# but stumble with interview questions? Let’s crush them together.
Facing tricky C# interview questions? No worries, I’ve been there.
The goal of the basic level C# job interview questions is to assess your understanding of core concepts and your ability to apply them in practical scenarios. Let’s conquer those C# job interview questions and land your dream job.
Basic C# Job Interview Questions
What is a namespace in C#?
A namespace is a way to organize your code and prevent naming conflicts. For example:
namespace MyApplication
{
class Program
{
static void Main(string[] args)
{
System.Console.WriteLine("Hello World");
}
}
}
This code defines a Program
class inside the MyApplication
namespace. Namespaces help manage the scope of classes and methods.
How do you create a variable in C#?
You declare a variable by specifying its type followed by its name. For instance:
int myNumber = 10;
This code creates an integer variable named myNumber
and assigns it the value of 10.
What is a method in C#?
A method is a block of code that performs a specific task. Here’s an example:
public int AddNumbers(int number1, int number2)
{
return number1 + number2;
}
This method, AddNumbers
, takes two integers as input and returns their sum.
Can you explain the static
keyword?
The static
keyword denotes that a member of a class is shared by all instances. For example:
class Program
{
static int counter = 0;
}
Here, counter
is a static variable. It’s shared among all instances of the Program
class.
What are access modifiers in C#?
Access modifiers control the visibility of class members. public
, private
, protected
, and internal
are examples.
public class Car
{
private int speed;
}
In this code, speed
is a private variable, meaning it can only be accessed within the Car
class.
How do you handle exceptions in C#?
You use try-catch blocks to handle exceptions. For example:
try
{
int[] myArray = {1, 2, 3};
Console.WriteLine(myArray[3]);
}
catch (IndexOutOfRangeException e)
{
Console.WriteLine("An exception occurred.");
}
This code catches an IndexOutOfRangeException
if an attempt is made to access an index not present in the array.
What is inheritance in C#?
Inheritance allows a class to inherit fields and methods from another class. Here’s an example:
class Vehicle
{
public string brand = "Ford";
}
class Car : Vehicle
{
public string modelName = “Mustang”;
}
Car
inherits Vehicle
, meaning it can access the brand
field.
Describe an interface in C#.
An interface is a contract that defines a set of methods without implementing them. Classes that implement the interface must define these methods.
interface IAnimal
{
void animalSound();
}
class Pig : IAnimal
{
public void animalSound()
{
Console.WriteLine(“The pig says: wee wee”);
}
}
Here, Pig
implements the IAnimal
interface, providing an implementation for animalSound
.
What is polymorphism in C#?
Polymorphism allows methods to do different things based on the object that is calling them.
class Animal
{
public virtual void animalSound()
{
Console.WriteLine("The animal makes a sound");
}
}
class Pig : Animal
{
public override void animalSound()
{
Console.WriteLine(“The pig says: wee wee”);
}
}
This demonstrates method overriding, a form of polymorphism.
Explain the Main
method in C#.
The Main
method is the entry point of a C# application.
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
This code prints “Hello World!” to the console. The Main
method is where execution starts.
How do you concatenate strings in C#?
You can use the
+
operator or the String.Concat
method.
string firstName = "John";
string lastName = "Doe";
string fullName = firstName + " " + lastName;
This code concatenates firstName
and lastName
into fullName
.
What is an array in C#?
An array is a collection of elements that are accessible by indexing.
int[] myArray = {1, 2, 3, 4, 5};
This code declares an array of integers.
How do you create a list in C#?
You can use the List<T>
class.
List<int> myList = new List<int>();
myList.Add(1);
myList.Add(2);
myList.Add(3);
This code creates a list of integers and adds three elements to it.
What is the difference between break
and continue
in C#?
break
exits the loop, while continue
skips the current iteration and proceeds to the next one.
for (int i = 0; i < 5; i++)
{
if (i == 2) continue;
if (i == 4) break;
Console.WriteLine(i);
}
This loop skips 2, prints 0, 1, 3, and stops before 4.
Explain the use of the var
keyword in C#.
var
is used for implicitly typed variables. The compiler determines the type.
var myVariable = "Hello";
Here, myVariable
is implicitly typed as string
by the compiler.
How do you read input from the console?
You use Console.ReadLine
for strings or Console.ReadKey
for single characters.
Console.WriteLine("Enter your name: ");
string name = Console.ReadLine();
This code reads a name from the console.
What is LINQ in C#?
LINQ (Language Integrated Query) is used to query collections in a declarative manner.
int[] scores = { 90, 71, 82, 93, 75, 82 };
var highScores = from score in scores where score > 80 select score;
highScores
will contain scores greater than 80.
Explain the out
keyword in C#.
out
is used for passing arguments by reference, allowing methods to return multiple values.
public void GetValues(out int x, out int y)
{
x = 5;
y = 10;
}
This method sets x
and y
to 5 and 10, respectively.
What is a constructor in C#?
A constructor is a special method that initializes a new instance of a class.
class Book
{
public string title;
public Book(string aTitle)
{
title = aTitle;
}
}
This constructor initializes Book
objects with a title.
How do you use the using
statement in C#?
The using
statement ensures the disposal of resources. It’s commonly used with files and streams.
using (StreamWriter writer = new StreamWriter("file.txt"))
{
writer.WriteLine("Hello World");
}
writer
is automatically disposed of after the block.
Explain encapsulation in C#.
Encapsulation hides the internal state of an object and requires that all interaction be done through an object’s methods.
class BankAccount
{
private double balance;
public void Deposit(double amount)
{
if (amount > 0)
{
balance += amount;
}
}
}
This BankAccount
class encapsulates the balance
field, controlling access through the Deposit
method.
These questions cover fundamental concepts in C# that every junior developer should understand.
Intermediate Level C# job interview questions
As we move into the intermediate level, I’ll be focusing on your ability to understand more complex C# concepts and apply them in practical scenarios. The questions will touch on various aspects, from LINQ and async programming to design patterns and unit testing.
Explain the difference between a struct
and a class
in C#.
Structs are value types, while classes are reference types. Structs are stored on the stack, which means they’re faster to access but have a limited lifetime. Classes are stored on the heap, which allows for dynamic memory allocation and garbage collection.
struct Point
{
public int X, Y;
}
class Circle
{
public Point Center;
public int Radius;
}
Point
is a struct representing a point in 2D space, while Circle
is a class that includes a Point
and a radius.
What is the significance of the async
and await
keywords?
They are used for asynchronous programming, allowing for non-blocking operations. This is particularly useful for I/O operations or tasks that take time to complete, improving application responsiveness.
public async Task<string> GetWebPageAsync(string url)
{
using (HttpClient client = new HttpClient())
{
string content = await client.GetStringAsync(url);
return content;
}
}
This method asynchronously fetches a webpage’s content, allowing other operations to continue while waiting for the response.
How does the IEnumerable
interface work in C#?
IEnumerable allows for simple iteration over a collection of a specified type. It’s the basis of LINQ querying and foreach loops in C#.
public IEnumerable<int> GetEvenNumbers(int[] numbers)
{
foreach (var number in numbers)
{
if (number % 2 == 0)
{
yield return number;
}
}
}
This method returns an enumerable of even numbers from an array, demonstrating the use of yield return
.
Can you explain how LINQ to SQL works?
LINQ to SQL translates language-integrated queries into SQL queries, allowing manipulation of databases using C#. It maps database tables to classes and rows to objects.
DataContext db = new DataContext(connectionString);
var query = from customer in db.GetTable<Customer>()
where customer.Name.StartsWith("J")
select customer;
This queries for customers whose names start with “J”, directly in C# code.
What is the purpose of the var
keyword in LINQ?
In LINQ, var
is used to hold query results. The actual type is determined by the compiler at compile time based on the query.
var results = from s in students
where s.Grade > 90
select s.Name;
results
holds the names of students with grades over 90, with its type inferred by the compiler.
Explain the use of extension methods.
Extension methods allow adding new methods to existing types without modifying them, enhancing functionality.
public static class StringExtensions
{
public static int WordCount(this string str)
{
return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length;
}
}
WordCount
is an extension method for string
, counting the words in a string.
How do you manage memory in C#?
Memory management in C# is primarily handled by the garbage collector (GC), which automatically frees memory occupied by objects no longer in use. However, for unmanaged resources, the IDisposable
interface and the Dispose
method should be implemented.
class FileManager : IDisposable
{
private FileStream file;
public FileManager(string fileName)
{
file = new FileStream(fileName, FileMode.OpenOrCreate);
}
public void Dispose()
{
file?.Dispose();
}
}
FileManager
manages a file resource and ensures it’s properly disposed of.
Describe the Observer pattern and its implementation in C#.
The Observer pattern allows objects to notify other objects about changes in their state. C# supports this pattern through the IObservable
and IObserver
interfaces.
“`csharp public class WeatherStation : IObservable
private List<IObserver<int>> observers = new List<IObserver<int>>();
public IDisposable Subscribe(IObserver<int> observer)
{
if (!observers.Contains(observer))
observers.Add(observer);
return new Unsubscriber(observers
, observer); }
public void Notify(int temp)
{
foreach (var observer in observers)
{
observer.OnNext(temp);
}
}
}
`WeatherStation` notifies subscribed observers about temperature changes.
What is the `Tuple` class, and how is it used?
`Tuple` is a class that provides an easy way to create a data structure holding an ordered set of elements.
```csharp
var person = Tuple.Create("John", "Doe", 30);
Console.WriteLine($"Name: {person.Item1} {person.Item2}, Age: {person.Item3}");
This creates a tuple representing a person and prints its elements.
How do you implement a generic method in C#?
Generic methods allow for code reusability with different data types.
public T Max<T>(T a, T b) where T : IComparable<T>
{
return a.CompareTo(b) > 0 ? a : b;
}
Max
is a generic method that returns the greater of two values, demonstrating the use of constraints with where
.
What is the Entity Framework in C#?
Entity Framework (EF) is an ORM (Object-Relational Mapping) framework for .NET, simplifying data manipulation by automatically mapping database tables to classes.
using (var context = new SchoolContext())
{
var student = new Student { Name = "John Doe" };
context.Students.Add(student);
context.SaveChanges();
}
This code snippet adds a new student to the database using EF.
Explain the concept of async
streams in C#.
async
streams allow for asynchronous iteration over collections that are not immediately available, useful for streaming data.
async IAsyncEnumerable<int> GetNumbersAsync()
{
for (int i = 0; i < 10; i++)
{
await Task.Delay(100); // Simulate async work
yield return i;
}
}
This method asynchronously returns numbers, demonstrating async
streams.
How do you perform dependency injection in C#?
Dependency injection (DI) is a technique to achieve inversion of control, making classes less dependent on each other. .NET Core provides built-in support for DI.
public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
}
HomeController
receives an ILogger
instance through constructor injection.
What is a nullable type in C#?
Nullable types allow value types to be null, providing a way to represent the absence of a value.
int? number = null;
if (number.HasValue)
{
Console.WriteLine(number.Value);
}
else
{
Console.WriteLine("No value");
}
This demonstrates checking and using a nullable int.
Describe the yield
keyword usage.
yield
is used with iterators to provide a value to the enumerator object or to signal the end of iteration.
public IEnumerable<int> GetPowersOfTwo(int n)
{
for (int i = 0; i < n; i++)
{
yield return (int)Math.Pow(2, i);
}
}
This method uses yield return
to generate powers of two, demonstrating an easy way to create enumerable sequences.
Explain exception filters in C#.
Exception filters allow handling exceptions based on a condition.
try
{
// Some operation
}
catch (Exception e) when (e.Message.Contains("specific error"))
{
// Handle specific error
}
This catches exceptions only when the condition in the when
clause is true.
How do you use the nameof
operator?
nameof
provides the string name of a variable, type, or member. This is useful for parameter validation and error handling, reducing the risk of typos in string literals.
public void DoSomething(string parameter)
{
if (parameter == null) throw new ArgumentNullException(nameof(parameter));
}
This throws an exception if parameter
is null, using nameof
to provide the parameter name.
What are expression-bodied members?
Expression-bodied members allow for more concise syntax for members that consist of a single expression.
public class Person
{
public
string Name { get; set; }
public override string ToString() => $"Name: {Name}";
}
ToString
is implemented as an expression-bodied member, simplifying the syntax.
How do you create and use indexers in C#?
Indexers allow objects to be indexed like arrays.
public class SampleCollection<T>
{
private T[] arr = new T[100];
public T this[int i]
{
get { return arr[i]; }
set { arr[i] = value; }
}
}
This class uses an indexer to access elements in its internal array.
Explain the concept and use of attributes in C#.
Attributes provide a powerful method to add metadata to code elements. This metadata can then be used at runtime via reflection.
[Serializable]
public class SampleClass
{
// Class members
}
SampleClass
is marked as serializable with an attribute, indicating it can be serialized.
What is the purpose of the volatile
keyword?
volatile
is used to indicate that a field might be modified by multiple threads that are executing at the same time. This ensures that the most up-to-date value is always read.
private volatile int flag = 0;
flag
is marked as volatile
, ensuring it is correctly updated across multiple threads.
These questions are designed to probe your understanding of intermediate C# concepts and their practical applications. Your responses will give insight into your problem-solving abilities and your approach to software development.
Advanced Level C# Job Interview Questions
For this advanced level, I expect you to demonstrate not only a deep understanding of C# and .NET framework but also an ability to tackle complex problems and optimize code performance. Let’s see how you handle these challenging scenarios and concepts.
Discuss the use and implications of async
/await
in high-performance applications.
Using async
/await
wisely prevents blocking on the main thread, improving responsiveness. However, misuse can lead to deadlocks, excessive thread pool usage, and scalability issues.
public async Task ProcessDataAsync()
{
var data = await ReadDataAsync().ConfigureAwait(false);
await ProcessDataAsync(data).ConfigureAwait(false);
}
ConfigureAwait(false)
is used here to avoid capturing the synchronization context, optimizing the thread pool usage.
Explain the significance of memory barriers in multithreaded applications.
Memory barriers prevent the CPU from reordering reads and writes to memory, ensuring memory operations occur as expected in a multithreaded environment.
volatile int _flag = 0;
int _value = 0;
public void Thread1()
{
_value = 5;
Thread.MemoryBarrier(); // Create a full fence
_flag = 1;
}
public void Thread2()
{
if (_flag == 1)
{
Thread.MemoryBarrier(); // Ensure correct ordering
Console.WriteLine(_value);
}
}
Thread.MemoryBarrier()
ensures that _value
is written before _flag
and read after _flag
, preventing reordering.
How can the Span<T>
type be used to enhance performance in .NET applications?
Span<T>
provides a type-safe, memory-efficient way of representing contiguous regions of arbitrary memory. It is particularly useful for slicing arrays and strings without allocation.
byte[] data = { 1, 2, 3, 4, 5 };
Span<byte> span = data.AsSpan().Slice(1, 3);
This slices the array without creating a new one, reducing memory allocations and enhancing performance.
Discuss the use of the Parallel
class for data parallelism.
The Parallel
class simplifies parallel execution of loops and tasks, automatically managing partitioning and threading. It’s ideal for operations that can be executed concurrently.
int[] numbers = { 1, 2, 3, 4, 5 };
Parallel.ForEach(numbers, number =>
{
Console.WriteLine(Math.Sqrt(number));
});
This parallelizes the operation of calculating the square root of each number, potentially speeding up execution on multi-core systems.
What are extension methods and how can they be used to extend existing classes?
Extension methods enable adding methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type.
public static class StringExtensions
{
public static bool IsCapitalized(this string input)
{
if (string.IsNullOrEmpty(input)) return false;
return char.IsUpper(input[0]);
}
}
IsCapitalized
can be called on any string
instance, providing additional functionality seamlessly.
Explain how C# 8.0’s default interface methods can be used for versioning interfaces.
Default interface methods allow interfaces to declare methods with an implementation. This helps evolve interfaces without breaking existing implementations.
public interface ILogger
{
void Log(string message);
void LogError(string message) => Log($"Error: {message}");
}
Implementers of ILogger
are not forced to implement LogError
, easing versioning concerns.
Describe the process and benefits of using source generators in C#.
Source generators allow for generating additional C# source code during compilation. They enable metaprogramming scenarios, reducing runtime overhead and manual coding errors.
// Imagine a source generator that auto-generates properties based on a custom attribute
Although a code example isn’t straightforward without creating the generator itself, imagine annotating a class with [AutoProperties]
to generate boilerplate property code.
How do you implement custom async streams with IAsyncEnumerable<T>
IAsyncEnumerable<T>
allows for asynchronous enumeration over sequences that are asynchronously obtained, useful for streaming data.
“`csharp public async IAsyncEnumerable
for (int i = 0; i < count; i++)
{
await Task.Delay(100); // Simulate async operation
yield return i;
}
}
This method generates a sequence of numbers asynchronously, demonstrating async iteration.
What are the advantages of using `ValueTask<T>` over `Task<T>`?
`ValueTask<T>` is a value type that represents a result that might already be available, avoiding unnecessary heap allocation and improving performance for synchronous paths in asynchronous methods.
```csharp
public async ValueTask<int> GetValueAsync(int number)
{
if (number < 0) return 0; // Synchronous path
await Task.Delay(100); // Asynchronous path
return number;
}
This method returns a value synchronously if possible, otherwise it waits asynchronously, showcasing ValueTask<T>
‘s efficiency.
Discuss strategies for managing large object heap (LOH) fragmentation in .NET applications.
LOH fragmentation can be mitigated by pooling large objects, reusing them instead of allocating new ones, and minimizing allocations of large objects. Additionally, .NET Core and later versions improve LOH management through automatic compaction.
// No direct code example for LOH management, but consider using ArrayPool<T> for reusing large arrays.
Using ArrayPool<T>
for buffering large data sets can help reduce LOH fragmentation.
How can you use pattern matching enhancements in C# 8.0 and above to simplify code?
Pattern matching enhancements, including property patterns and tuple patterns, simplify complex conditional logic.
public static string GetQuadrant(Point point) => point switch
{
{ X: > 0, Y: > 0 } => "Quadrant 1",
{ X: < 0, Y: > 0 } => "Quadrant 2",
{ X: < 0, Y: < 0 } => "Quadrant 3",
{ X: > 0, Y: < 0 } => "Quadrant 4",
_ => "Origin"
};
This uses property patterns in a switch expression to determine a point’s quadrant, showcasing cleaner syntax for complex conditions.
Explain the concept of record types in C# 9.0 and their use cases.
Records are immutable reference types that provide value-based equality. They’re ideal for modeling immutable data.
public record Person(string FirstName, string LastName);
Person
is a record that automatically supports value-based equality and deconstruction, simplifying data modeling.
How does the System.Text.Json
namespace improve JSON serialization/deserialization performance?
System.Text.Json
offers high-performance, low-allocation serialization and deserialization for JSON. It’s optimized for speed and minimal memory footprint, supporting asynchronous I/O.
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var person = JsonSerializer.Deserialize<Person>(jsonString, options);
This demonstrates deserializing a JSON string with case-insensitive property names, utilizing System.Text.Json
for efficient parsing.
Discuss the improvements of nullable reference types introduced in C# 8.0.
Nullable reference types enable developers to explicitly declare whether a reference type is nullable, improving null safety and reducing the risk of null reference exceptions.
#nullable enable
string? nullableString = null;
string nonNullableString = "Hello";
This enforces compile-time checks for potential null reference assignments, enhancing code safety.
What are the performance implications of using reflection, and how can you mitigate them?
Reflection is powerful but can be slow due to its runtime type inspection capabilities. Caching reflection results and using Expression<T>
to compile expressions into delegates can mitigate performance penalties.
var propertyInfo = typeof(Person).GetProperty(nameof(Person.FirstName));
var compiled = (Func<Person, string>)Expression.Property(Expression.Parameter(typeof(Person), "p"), propertyInfo).Compile();
This compiles a property access into a delegate, reducing the overhead of reflection in critical paths.
How can ConcurrentDictionary
enhance thread-safe operations
ConcurrentDictionary
is designed for high-performance, thread-safe operations on a key/value collection, automatically handling locking and synchronization.
var dictionary = new ConcurrentDictionary<int, string>();
dictionary.TryAdd(1, "One");
This provides a thread-safe way to work with collections in concurrent environments, without manual lock management.
Explain the use of Channels
for producer-consumer scenarios in .NET Core.
Channels provide a thread-safe way to transfer data between producing and consuming tasks, supporting both synchronous and asynchronous data consumption.
```csharp
var channel = Channel.CreateUnbounded<string>();
await channel.Writer.WriteAsync("message");
var message = await channel.Reader.ReadAsync();
```
This enables asynchronous message passing between producer and consumer tasks, efficiently handling concurrent workflows.
Discuss the advantages of immutability in C# and how it’s achieved.
Immutability enhances code clarity, thread safety, and reduces bugs by ensuring objects cannot change state after creation. Immutable types, records, and read-only structures are key to achieving immutability.
public readonly struct ImmutablePoint
{
public int X { get; }
public int Y { get; }
public ImmutablePoint(int x, int y) => (X, Y) = (x, y);
}
ImmutablePoint
demonstrates a simple immutable structure, ensuring thread-safe operations.
How do custom attributes work, and give an example of creating one?
Custom attributes allow attaching metadata to code elements, which can be examined at runtime using reflection.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyCustomAttribute : Attribute
{
public string Description { get; set; }
}
MyCustomAttribute
can be used to annotate classes or methods with a description, demonstrating extensibility through metadata.
What is the purpose of the IAsyncDisposable
interface?
IAsyncDisposable
provides a mechanism for releasing unmanaged resources asynchronously, useful in scenarios where disposal operations are I/O-bound.
public async ValueTask DisposeAsync()
{
await DisposeAsyncCore();
Dispose(false);
GC.SuppressFinalize(this);
}
This pattern ensures resources are disposed of asynchronously, complementing the async
programming model.
Explain the benefits and use cases of the ReadOnlySpan<T>
type.
ReadOnlySpan<T>
represents a contiguous region of memory, similar to Span<T>
, but for read-only access. It’s ideal for performance-critical scenarios where modifying data is unnecessary or undesirable.
void PrintFirstThreeBytes(byte[] data)
{
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(data, 0, 3);
foreach (byte b in span) Console.WriteLine(b);
}
This method demonstrates using ReadOnlySpan<T>
to access a slice of a byte array without copying, optimizing memory usage and performance.
These questions are tailored to probe your advanced understanding of C# and .NET, focusing on performance optimization, modern language features, and complex problem-solving abilities. Your ability to navigate these topics will be crucial in our fast-paced development environment.