15 C#.NET Interview Questions and Answers
Prepare for your C#.NET interview with this guide, featuring curated questions and answers to enhance your understanding and confidence.
Prepare for your C#.NET interview with this guide, featuring curated questions and answers to enhance your understanding and confidence.
C#.NET is a versatile and powerful programming language developed by Microsoft, widely used for building a variety of applications, including web, desktop, and mobile solutions. Its strong typing, object-oriented features, and seamless integration with the .NET framework make it a preferred choice for developers working on enterprise-level projects. The language’s robust ecosystem and extensive libraries enable efficient development and maintenance of scalable applications.
This article aims to prepare you for your upcoming C#.NET interview by providing a curated selection of questions and answers. By familiarizing yourself with these topics, you will gain a deeper understanding of C#.NET’s core concepts and practical applications, enhancing your confidence and readiness for technical discussions.
Garbage collection in .NET is managed by the Common Language Runtime (CLR), which automatically handles memory allocation and release for applications. The garbage collector (GC) operates on the principle of generational collection, dividing objects into three generations: Generation 0 for short-lived objects, Generation 1 for objects that have survived one GC cycle, and Generation 2 for long-lived objects. The GC process involves marking objects in use, updating references, and compacting memory to reduce fragmentation. While the GC runs automatically, developers can manually trigger it using GC.Collect()
, though this is generally discouraged due to potential performance issues.
In C#.NET, async
and await
keywords facilitate writing asynchronous code. The async
keyword declares a method as asynchronous, while await
pauses execution until the awaited task completes, allowing the program to remain responsive. For example:
public async Task<string> FetchDataAsync(string url) { using (HttpClient client = new HttpClient()) { HttpResponseMessage response = await client.GetAsync(url); response.EnsureSuccessStatusCode(); string responseData = await response.Content.ReadAsStringAsync(); return responseData; } } public async Task MainMethod() { string data = await FetchDataAsync("https://example.com"); Console.WriteLine(data); }
Here, FetchDataAsync
uses await
to handle an HTTP GET request asynchronously, and MainMethod
waits for its completion.
Delegates in C#.NET are type-safe pointers to methods, used for passing methods as arguments, defining callbacks, and implementing event handling. A delegate references a method matching its signature. For example:
using System; public delegate void DisplayMessage(string message); public class Program { public static void Main() { DisplayMessage messageDelegate = ShowMessage; messageDelegate("Hello, World!"); } public static void ShowMessage(string message) { Console.WriteLine(message); } }
Here, DisplayMessage
references methods with a single string parameter and void return type, like ShowMessage
.
Abstract classes and interfaces in C#.NET define methods for derived classes but differ in characteristics. Abstract classes can contain both abstract and concrete methods, fields, constructors, and support access modifiers. Interfaces only contain method signatures, properties, events, and indexers without implementation, and all members are implicitly public. For example:
// Abstract Class public abstract class Animal { public abstract void MakeSound(); public void Sleep() { Console.WriteLine("Sleeping..."); } } // Interface public interface IAnimal { void MakeSound(); } public class Dog : Animal, IAnimal { public override void MakeSound() { Console.WriteLine("Bark"); } }
Dependency injection (DI) in C#.NET allows an object to receive its dependencies, typically through constructors, properties, or methods. DI decouples class creation from its dependencies, enhancing modularity and testability. For example:
public interface IService { void Serve(); } public class Service : IService { public void Serve() { Console.WriteLine("Service Called"); } } public class Client { private readonly IService _service; public Client(IService service) { _service = service; } public void Start() { _service.Serve(); } } // In a DI container setup var service = new Service(); var client = new Client(service); client.Start();
Here, Client
depends on IService
, receiving it through its constructor.
Custom attributes in C#.NET add metadata to code elements, accessible at runtime using reflection. They are created by defining a class inheriting from System.Attribute
. For example:
using System; [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class MyCustomAttribute : Attribute { public string Description { get; } public MyCustomAttribute(string description) { Description = description; } } [MyCustomAttribute("This is a sample class with a custom attribute.")] public class SampleClass { [MyCustomAttribute("This is a sample method with a custom attribute.")] public void SampleMethod() { Console.WriteLine("SampleMethod executed."); } } class Program { static void Main() { var type = typeof(SampleClass); var classAttributes = type.GetCustomAttributes(typeof(MyCustomAttribute), false); foreach (MyCustomAttribute attr in classAttributes) { Console.WriteLine($"Class Attribute Description: {attr.Description}"); } var method = type.GetMethod("SampleMethod"); var methodAttributes = method.GetCustomAttributes(typeof(MyCustomAttribute), false); foreach (MyCustomAttribute attr in methodAttributes) { Console.WriteLine($"Method Attribute Description: {attr.Description}"); } } }
Here, MyCustomAttribute
is applied to SampleClass
and SampleMethod
, with descriptions retrieved using reflection.
The Common Language Runtime (CLR) is the execution engine for .NET applications, providing services like memory management, security, exception handling, JIT compilation, type safety, and interoperability with unmanaged code.
Multi-threading in C# allows concurrent execution of threads, improving resource use and performance. The .NET framework provides classes like Thread
, ThreadPool
, and Task
Parallel Library (TPL) for handling multi-threading. Synchronization is essential to avoid race conditions, using constructs like lock
, Monitor
, Mutex
, and Semaphore
. For example:
using System; using System.Threading; class Program { static void Main() { Thread thread = new Thread(new ThreadStart(DoWork)); thread.Start(); thread.Join(); } static void DoWork() { Console.WriteLine("Work is being done on a separate thread."); } }
And for synchronization:
class Program { private static readonly object _lock = new object(); static void Main() { Thread thread1 = new Thread(new ThreadStart(DoWork)); Thread thread2 = new Thread(new ThreadStart(DoWork)); thread1.Start(); thread2.Start(); thread1.Join(); thread2.Join(); } static void DoWork() { lock (_lock) { Console.WriteLine("Thread-safe work is being done."); } } }
Generics in C#.NET allow defining classes, methods, delegates, and interfaces with a placeholder for data types, enhancing code reusability and type safety. For example:
List<int> intList = new List<int>(); intList.Add(1); intList.Add(2); List<string> stringList = new List<string>(); stringList.Add("Hello"); stringList.Add("World");
Here, List<T>
is a generic class that can store any data type, avoiding the need for separate classes for each type.
Reflection in C#.NET enables runtime examination and manipulation of object types using the System.Reflection namespace. For example:
using System; using System.Reflection; public class Example { public void PrintMessage() { Console.WriteLine("Hello, Reflection!"); } } public class Program { public static void Main() { Type type = typeof(Example); MethodInfo method = type.GetMethod("PrintMessage"); object instance = Activator.CreateInstance(type); method.Invoke(instance, null); } }
Here, reflection retrieves the PrintMessage
method and invokes it on an Example
instance.
The singleton pattern in C# restricts a class to a single instance, providing a global access point. For example:
public class Singleton { private static Singleton instance = null; private static readonly object padlock = new object(); Singleton() { } public static Singleton Instance { get { lock (padlock) { if (instance == null) { instance = new Singleton(); } return instance; } } } }
Here, the constructor is private, and a static variable holds the single instance, with a lock ensuring thread safety.
In ASP.NET Core, state management in web applications can be achieved through session state, cookies, distributed cache, and TempData. For example, configuring session state in Startup.cs
:
public void ConfigureServices(IServiceCollection services) { services.AddDistributedMemoryCache(); services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(30); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); services.AddControllersWithViews(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseSession(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); }
Middleware in ASP.NET Core builds a request pipeline where each component can handle an HTTP request or response. To implement middleware, define a class with an Invoke
or InvokeAsync
method and add it to the pipeline in the Startup
class. For example:
public class CustomMiddleware { private readonly RequestDelegate _next; public CustomMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { await context.Response.WriteAsync("Before Middleware\n"); await _next(context); await context.Response.WriteAsync("After Middleware\n"); } } public class Startup { public void Configure(IApplicationBuilder app) { app.UseMiddleware<CustomMiddleware>(); app.Run(async (context) => { await context.Response.WriteAsync("Hello from the terminal middleware.\n"); }); } }
Here, CustomMiddleware
writes text to the response before and after calling the next middleware.
Unit testing in C# involves testing individual units of code using frameworks like NUnit or MSTest. To write and run unit tests, create a test project, add a reference to the project to be tested, write test methods, and run them using a test runner. For example, using NUnit:
using NUnit.Framework; namespace MyProject.Tests { [TestFixture] public class CalculatorTests { [Test] public void Add_WhenCalled_ReturnsSum() { var calculator = new Calculator(); var result = calculator.Add(1, 2); Assert.AreEqual(3, result); } } }
Here, CalculatorTests
contains a test method Add_WhenCalled_ReturnsSum
that tests the Add
method of the Calculator
class.
To build a RESTful service in .NET, use ASP.NET Core. Create a new Web API project, define models and controllers, implement CRUD operations, and configure routing and middleware. For example, a simple controller:
[ApiController] [Route("api/[controller]")] public class ProductsController : ControllerBase { private readonly List<Product> _products = new List<Product> { new Product { Id = 1, Name = "Product1", Price = 10 }, new Product { Id = 2, Name = "Product2", Price = 20 } }; [HttpGet] public ActionResult<IEnumerable<Product>> GetProducts() { return _products; } [HttpGet("{id}")] public ActionResult<Product> GetProduct(int id) { var product = _products.FirstOrDefault(p => p.Id == id); if (product == null) { return NotFound(); } return product; } [HttpPost] public ActionResult<Product> CreateProduct(Product product) { _products.Add(product); return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, product); } }
To consume a RESTful service, use the HttpClient class. For example:
public async Task<Product> GetProductAsync(int id) { using (var client = new HttpClient()) { client.BaseAddress = new Uri("https://example.com/api/"); var response = await client.GetAsync($"products/{id}"); response.EnsureSuccessStatusCode(); var product = await response.Content.ReadAsAsync<Product>(); return product; } }