C# Intermediate
C# Intermediate Interview with follow-up questions
1. Can you explain what namespaces are in C#?
Namespaces organize types into logical groups and prevent naming conflicts when multiple libraries define types with the same name.
Declaration styles:
// Traditional block-scoped namespace
namespace MyCompany.MyApp.Services
{
public class UserService { }
}
// File-scoped namespace (C# 10+) — applies to the entire file, no extra indentation
namespace MyCompany.MyApp.Services;
public class UserService { }
File-scoped namespaces (the single-line form) are preferred in modern C# projects because they reduce indentation.
Using directives:
using System; // imports namespace
using System.Collections.Generic;
using static System.Math; // imports static members (e.g., use Sqrt() instead of Math.Sqrt())
using MyAlias = System.Collections.Generic.Dictionary; // alias
Global usings (C# 10+): declared once, apply to all files in the project:
// In GlobalUsings.cs or any .cs file
global using System;
global using Microsoft.Extensions.Logging;
.NET 6+ SDK projects auto-generate global using directives for common namespaces (System, System.Linq, System.Threading.Tasks, etc.) via the enable project property — enabled by default in new projects.
Nested namespaces are fully qualified with dots: MyApp.Data.Repositories. There's no requirement that the folder structure matches the namespace, though it's convention (and enforced by analyzers in many projects).
Common .NET namespaces to know:
System— primitives, Console, Math, EnvironmentSystem.Collections.Generic— List, Dictionary, HashSetSystem.Linq— LINQ extension methodsSystem.Threading.Tasks— Task, TaskSystem.Text.Json— JSON serialization (built-in since .NET Core 3.0)Microsoft.Extensions.DependencyInjection— DI container
Interviewers probe: using for namespace import vs using statement for resource management (IDisposable) — these are two completely different language features that share the keyword.
Follow-up 1
How do you use namespaces in your code?
To use a namespace in your code, you need to include a 'using' directive at the top of your file. This allows you to reference types from that namespace without having to fully qualify their names. For example, if you have a namespace called 'MyNamespace' and it contains a class called 'MyClass', you can use 'using MyNamespace;' at the top of your file and then simply refer to 'MyClass' in your code.
Follow-up 2
What is the 'using' directive in C#?
The 'using' directive in C# is used to create a shortcut for referencing types from a particular namespace. It eliminates the need to fully qualify the names of types from that namespace. The 'using' directive is typically placed at the top of a file and can be used for multiple namespaces. For example, 'using System;' allows you to reference types from the 'System' namespace without having to write 'System' before each type.
Follow-up 3
Can you give an example of defining a namespace?
Sure! Here's an example of defining a namespace in C#:
namespace MyNamespace
{
class MyClass
{
// Class implementation
}
}
In this example, we define a namespace called 'MyNamespace' and within it, we define a class called 'MyClass'. The namespace and class can have any valid names you choose.
Follow-up 4
What is the purpose of the 'global' namespace?
The 'global' namespace in C# is the root namespace for all other namespaces. It is used to provide a global scope for types that are not explicitly declared within a namespace. Types defined in the 'global' namespace can be accessed from any other namespace without the need for a 'using' directive. However, it is generally recommended to define types within specific namespaces to avoid naming conflicts and improve code organization.
2. What are classes and objects in C#?
A class is a blueprint that defines the structure and behavior of objects. An object is an instance of that class — a concrete entity in memory with its own state.
Class anatomy:
public class BankAccount
{
// Fields (private by convention)
private decimal _balance;
// Auto-property
public string Owner { get; init; } // init-only: settable at construction, then readonly
// Constructor
public BankAccount(string owner, decimal initialBalance)
{
Owner = owner;
_balance = initialBalance;
}
// Method
public void Deposit(decimal amount)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(amount);
_balance += amount;
}
// Computed property
public decimal Balance => _balance;
}
// Object creation
var account = new BankAccount("Alice", 1000m);
var account2 = new BankAccount { Owner = "Bob" }; // object initializer (requires public setter or init)
Modern alternatives to plain classes:
- Records (C# 9+) — immutable reference types with value-based equality and concise syntax:
csharp record Person(string Name, int Age); var alice = new Person("Alice", 30); var alice2 = alice with { Age = 31 }; // non-destructive mutation - Record structs (C# 10+) — same but value type:
readonly record struct Point(double X, double Y); - Target-typed
new(C# 9+):BankAccount account = new("Alice", 1000m);— type inferred from variable.
Access modifiers for class members: public, private (default), protected, internal, protected internal, private protected.
Static members belong to the type, not instances: static int Count;, static void Helper().
Interviewers probe: when would you use a record instead of a class? Records are ideal for DTOs, value objects, and immutable data — they provide Equals, GetHashCode, ToString, and deconstruction for free.
Follow-up 1
How do you define a class in C#?
To define a class in C#, you use the class keyword followed by the class name. Here's an example:
public class MyClass
{
// class members
}
Follow-up 2
How do you create an object in C#?
To create an object in C#, you use the new keyword followed by the class name and parentheses. Here's an example:
MyClass myObject = new MyClass();
Follow-up 3
Can you give an example of a class with properties and methods?
Sure! Here's an example of a class called Person with properties and methods:
public class Person
{
// properties
public string Name { get; set; }
public int Age { get; set; }
// methods
public void SayHello()
{
Console.WriteLine("Hello!");
}
}
Follow-up 4
What is the difference between a class and an object?
In C#, a class is a blueprint or a template for creating objects. It defines the properties, methods, and events that an object of that class will have. An object, on the other hand, is an instance of a class. It is created from the class blueprint and can have its own unique values for the properties defined in the class.
3. Can you explain exception handling in C#?
Exception handling in C# uses try/catch/finally to respond to runtime errors without crashing the application.
Basic structure:
try
{
var data = File.ReadAllText("config.json");
// ... process data
}
catch (FileNotFoundException ex)
{
Console.WriteLine($"File not found: {ex.FileName}");
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine($"Permission denied: {ex.Message}");
throw; // rethrow preserving original stack trace
}
catch (Exception ex) when (ex.Message.Contains("timeout")) // exception filter
{
Logger.LogWarning("Timeout occurred");
}
finally
{
// Always runs — cleanup code here
}
Key rules and gotchas:
- Catch most-specific first —
FileNotFoundExceptionbeforeIOExceptionbeforeException. throwvsthrow ex— barethrowpreserves the original stack trace;throw exresets it to the current line, losing valuable diagnostic information. Always use barethrowwhen rethrowing.- Exception filters (
whenclause) — evaluate before the catch block runs; don't unwind the stack if the filter returns false; useful for conditional handling and logging. finally— always executes (even afterreturn), ideal for cleanup. Preferusing/await usingoverfinallyforIDisposablecleanup.
Modern helpers (.NET 6+):
ArgumentNullException.ThrowIfNull(value);
ArgumentOutOfRangeException.ThrowIfNegative(amount);
Async exception handling: exceptions in async methods are captured in the returned Task and rethrown when awaited. For Task.WhenAll, exceptions are aggregated in AggregateException — use try/catch on the await to catch the first, or inspect ex.InnerExceptions for all.
Custom exceptions: inherit from Exception, add a constructor accepting string message and Exception? innerException:
public class OrderNotFoundException(int orderId)
: Exception($"Order {orderId} not found") { }
Interviewers probe: what's wrong with catching Exception at every level? (Swallows unexpected errors, makes debugging harder.) When is it appropriate? (Top-level global handler for logging before graceful shutdown.)
Follow-up 1
What are the key keywords used in exception handling?
The key keywords used in exception handling in C# are:
- try: The try block is used to enclose the code that may throw an exception.
- catch: The catch block is used to catch and handle the exception. It specifies the type of exception to catch.
- finally: The finally block is used to specify code that should always be executed, regardless of whether an exception occurred or not.
- throw: The throw keyword is used to manually throw an exception.
- throw ex: The throw ex statement rethrows the exception, preserving the original stack trace.
Follow-up 2
What is the difference between 'throw' and 'throw ex' in exception handling?
In exception handling, 'throw' and 'throw ex' are used to manually throw an exception. The main difference between them is that 'throw' preserves the original stack trace, while 'throw ex' resets the stack trace.
When you use 'throw' to rethrow an exception, the original stack trace is preserved. This means that when the exception is caught and the stack trace is examined, it will show the original location where the exception was thrown.
On the other hand, when you use 'throw ex' to rethrow an exception, the stack trace is reset. This means that when the exception is caught and the stack trace is examined, it will show the location where the exception was rethrown, rather than the original location.
Follow-up 3
Can you give an example of a try-catch-finally block?
Sure! Here's an example of a try-catch-finally block in C#:
try
{
// Code that may throw an exception
}
catch (Exception ex)
{
// Handle the exception
}
finally
{
// Code that should always be executed
}
In this example, the code that may throw an exception is placed inside the try block. If an exception occurs, it is caught by the catch block, where you can handle the exception. The finally block is used to specify code that should always be executed, regardless of whether an exception occurred or not.
Follow-up 4
What is the use of the 'finally' block in exception handling?
The 'finally' block in exception handling is used to specify code that should always be executed, regardless of whether an exception occurred or not. It is optional and can be used in conjunction with the try and catch blocks.
The 'finally' block is commonly used to release resources that were acquired in the try block, such as closing files or database connections. It ensures that the cleanup code is executed even if an exception occurs.
Here's an example:
try
{
// Code that may throw an exception
}
catch (Exception ex)
{
// Handle the exception
}
finally
{
// Code that should always be executed, e.g. releasing resources
}
4. What are properties and indexers in C#?
Properties and indexers are member types that provide controlled access to an object's data while allowing logic to be added transparently.
Properties:
public class Person
{
private int _age;
// Full property with validation
public int Age
{
get => _age;
set
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value));
_age = value;
}
}
// Auto-property
public string Name { get; set; } = string.Empty;
// Init-only (C# 9+) — settable in constructor/object initializer only
public string Id { get; init; } = Guid.NewGuid().ToString();
// Computed / expression-bodied
public string DisplayName => $"{Name} (age {Age})";
// Required (C# 11+) — must be set in object initializer
public required string Email { get; set; }
}
Property gotcha: always prefer properties over public fields in public APIs. Properties are binary-compatible extension points — you can add logic (validation, notification) later without breaking callers. Public fields cannot.
Indexers allow a class to be accessed with array-like syntax using this:
public class WordDictionary
{
private readonly Dictionary _data = new();
public string this[string key]
{
get => _data.TryGetValue(key, out var val) ? val : string.Empty;
set => _data[key] = value;
}
}
var dict = new WordDictionary();
dict["hello"] = "bonjour";
Console.WriteLine(dict["hello"]); // bonjour
Indexers can have multiple parameters (this[int row, int col]) and multiple overloads. The .NET BCL uses indexers extensively (list[0], dict["key"], span[1..3]).
Interviewers probe: what is the difference between a property and a field? (Properties can have logic, are bindable in UI frameworks, support change notification, and are interface members — fields cannot be interface members.) What are init-only setters used for? (Immutable-after-construction objects that still allow object initializer syntax.)
Follow-up 1
How do you define a property in C#?
In C#, you can define a property using the get and set accessors. The get accessor is used to retrieve the value of the property, and the set accessor is used to assign a new value to the property. Here's an example:
public string Name
{
get { return _name; }
set { _name = value; }
}
In this example, the Name property has a get accessor that returns the value of the private field _name, and a set accessor that assigns a new value to _name.
Follow-up 2
What is the difference between a property and a variable?
A property and a variable are both used to store and access data, but there are some differences between them:
- A variable is a storage location that holds a value, while a property is a combination of a field and methods that provide access to that field.
- A variable can be accessed directly, while a property provides a way to control the access to the underlying data.
- A property can have additional logic in its accessors, such as validation or calculation, while a variable does not.
In summary, properties provide a more controlled and flexible way to access and manipulate data compared to variables.
Follow-up 3
Can you give an example of an indexer?
Sure! An indexer allows you to access elements of a collection or class using an index. Here's an example of an indexer in C#:
public class MyCollection
{
private string[] _data = new string[10];
public string this[int index]
{
get { return _data[index]; }
set { _data[index] = value; }
}
}
In this example, the MyCollection class has an indexer that allows you to get or set elements of the private _data array using an index. For example, you can access the element at index 0 using myCollection[0].
Follow-up 4
What is the use of indexers in C#?
Indexers are useful when you want to provide a way to access elements of a collection or class using an index, similar to how you access elements of an array. They allow you to define custom logic for getting and setting values based on the index. Indexers are commonly used in classes that represent collections, such as lists or dictionaries, to provide a more convenient and intuitive way to access the elements. They also allow you to encapsulate the internal data structure of the collection and provide a consistent interface for accessing the elements.
5. Can you explain file I/O operations in C#?
File I/O in C# is handled primarily through types in the System.IO namespace. Modern .NET strongly favors async I/O in any environment where blocking a thread has cost (web servers, desktop apps).
High-level File class (simplest for small files):
// Read entire file async
string content = await File.ReadAllTextAsync("config.json");
// Write entire file async
await File.WriteAllTextAsync("output.txt", content);
// Read lines lazily (avoids loading entire file into memory)
foreach (string line in File.ReadLines("large.csv"))
{
Process(line);
}
// Async lazy reading (C# 8+, IAsyncEnumerable)
// Use StreamReader for true async line-by-line
StreamReader / StreamWriter for streaming:
await using var reader = new StreamReader("data.txt");
string? line;
while ((line = await reader.ReadLineAsync()) != null)
{
Console.WriteLine(line);
}
await using (C# 8+) calls DisposeAsync() — use it for async-disposable streams.
FileStream for binary data:
await using var fs = new FileStream("data.bin", FileMode.Open, FileAccess.Read,
FileShare.Read, bufferSize: 4096, useAsync: true);
byte[] buffer = new byte[4096];
int bytesRead = await fs.ReadAsync(buffer);
Path handling:
string path = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments), "file.txt");
string ext = Path.GetExtension(path); // ".txt"
string dir = Path.GetDirectoryName(path)!;
Always use Path.Combine() — never string concatenation for paths.
JSON (built-in since .NET Core 3.0):
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var person = await JsonSerializer.DeserializeAsync(stream, options);
Interviewers probe: why use async file I/O in ASP.NET Core? — Synchronous file reads block a thread pool thread, reducing the number of concurrent requests the server can handle. Async I/O releases the thread while waiting for the OS to return data.
Follow-up 1
What namespaces are used for file I/O operations?
The System.IO namespace is used for file I/O operations in C#. This namespace contains classes and methods for working with files, directories, and streams.
Follow-up 2
How do you read from a file in C#?
To read from a file in C#, you can use the StreamReader class from the System.IO namespace. Here's an example:
string filePath = "path/to/file.txt";
using (StreamReader reader = new StreamReader(filePath))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
Follow-up 3
How do you write to a file in C#?
To write to a file in C#, you can use the StreamWriter class from the System.IO namespace. Here's an example:
string filePath = "path/to/file.txt";
using (StreamWriter writer = new StreamWriter(filePath))
{
writer.WriteLine("Hello, World!");
}
Follow-up 4
Can you give an example of file I/O operations?
Sure! Here's an example that demonstrates both reading from a file and writing to a file:
string sourceFilePath = "path/to/source.txt";
string destinationFilePath = "path/to/destination.txt";
using (StreamReader reader = new StreamReader(sourceFilePath))
using (StreamWriter writer = new StreamWriter(destinationFilePath))
{
string line;
while ((line = reader.ReadLine()) != null)
{
writer.WriteLine(line);
}
}
6. What is the difference between `==` and `.Equals()` in C#?
This is a frequent interview question because the answer has several layers:
For value types:
Both == and .Equals() compare values by default (content equality). Structs inherit Equals() from System.ValueType which uses reflection-based field comparison (slow) — override it for custom structs.
For reference types:
==by default compares references (same object in memory).Equals()by default also compares references (inherited fromSystem.Object)- Unless overridden —
stringoverrides both to compare content
string a = new string('h', 5); // "hhhhh"
string b = new string('h', 5);
Console.WriteLine(a == b); // True — string overloads ==
Console.WriteLine(a.Equals(b)); // True — string overrides Equals
Console.WriteLine(ReferenceEquals(a, b)); // False — different objects
ReferenceEquals(a, b) always checks physical reference equality, regardless of overloads.
For custom classes: override both Equals(object?) and GetHashCode() together (they must be consistent — objects that are equal must have the same hash code). C# records do this automatically.
IEquatable: implement for type-safe, non-boxing equality comparison. Equals(T other) avoids boxing value types.
Gotcha — == with null:
string? s = null;
Console.WriteLine(s == null); // True
Console.WriteLine(null == s); // True (commutative for string)
s?.Equals(null); // null — safe call
Avoid s.Equals(null) when s might be null — throws NullReferenceException. Use string.Equals(s, null) or s is null (pattern matching, recommended in modern C#).
Live mock interview
Mock interview: C# Intermediate
- Read your scene and goals
- Talk it out; goals tick off live
- Get a score and stronger lines
Your voice and your AI key never touch our servers; the key stays in this browser and is sent only to Google. Only your round scores are saved to track progress.