15 C# .NET Interview Questions and Answers
Prepare for your next technical interview with our comprehensive guide on C# .NET, featuring expert insights and practice questions.
Prepare for your next technical interview with our comprehensive guide on C# .NET, featuring expert insights and practice questions.
C# .NET is a powerful and versatile framework developed by Microsoft, widely used for building robust applications across various platforms, including web, desktop, and mobile. Known for its strong typing, object-oriented features, and seamless integration with the Windows ecosystem, C# .NET has become a staple in enterprise environments and large-scale software projects. Its extensive libraries and tools make it a preferred choice for developers aiming to create high-performance, scalable applications.
This article offers a curated selection of C# .NET interview questions designed to help you demonstrate your proficiency and understanding of the framework. By reviewing these questions and their detailed answers, you can better prepare for technical interviews, showcasing your ability to solve complex problems and implement effective solutions using C# .NET.
The .NET framework is a software development platform developed by Microsoft. It consists of several key components:
Garbage collection in .NET is an automatic memory management feature that reclaims memory occupied by objects no longer in use. The .NET garbage collector (GC) operates on the managed heap and uses a generational approach to optimize the process.
The managed heap is divided into three generations:
The garbage collector identifies unreachable objects, reclaims their memory, and compacts remaining objects to reduce fragmentation. The GC operates in the background and can be triggered explicitly using the GC.Collect()
method, though this is generally not recommended.
Async and await in C# simplify asynchronous programming by allowing code to look synchronous while running asynchronously. The async
keyword declares a method as asynchronous, and the await
keyword pauses execution until the awaited task completes.
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); }
In this example, FetchDataAsync is an asynchronous method that fetches data from a URL. The await
keyword waits for the completion of the GetAsync and ReadAsStringAsync methods. The MainMethod calls FetchDataAsync and awaits its completion.
In C# .NET, events allow a class to notify other classes or objects when something of interest occurs. Events are based on delegates, which are type-safe pointers to methods. To subscribe to an event, you attach a method using the += operator. To raise an event, you invoke the delegate associated with the event.
Example:
using System; public class Publisher { public delegate void NotifyEventHandler(object sender, EventArgs e); public event NotifyEventHandler Notify; public void RaiseEvent() { Notify?.Invoke(this, EventArgs.Empty); } } public class Subscriber { public void OnNotify(object sender, EventArgs e) { Console.WriteLine("Event received."); } } public class Program { public static void Main() { Publisher publisher = new Publisher(); Subscriber subscriber = new Subscriber(); publisher.Notify += subscriber.OnNotify; publisher.RaiseEvent(); } }
In this example, the Publisher
class declares a delegate NotifyEventHandler
and an event Notify
. The RaiseEvent
method raises the event by invoking the delegate. The Subscriber
class has a method OnNotify
that handles the event.
In C# .NET, an assembly is a compiled code library used for deployment, versioning, and security. It can be a .dll or .exe file. Assemblies contain managed code modules, metadata, and resources like images and strings needed by the application.
Assemblies are important for several reasons:
Reflection in C# .NET allows you to inspect and interact with the metadata of assemblies, modules, and types at runtime. This is useful for tasks such as dynamically creating instances of types, invoking methods, and accessing fields and properties.
Example use case:
using System; using System.Reflection; public class Example { public void SayHello(string name) { Console.WriteLine($"Hello, {name}!"); } } public class Program { public static void Main() { Type type = typeof(Example); object instance = Activator.CreateInstance(type); MethodInfo methodInfo = type.GetMethod("SayHello"); methodInfo.Invoke(instance, new object[] { "World" }); } }
In this example, reflection is used to dynamically create an instance of the Example
class and invoke its SayHello
method.
Generics in C# .NET are defined using angle brackets <>
and a type parameter. This allows you to create classes, methods, and interfaces that can operate on any data type while maintaining type safety.
Example:
public class GenericList<T> { private List<T> _items = new List<T>(); public void Add(T item) { _items.Add(item); } public T Get(int index) { return _items[index]; } } GenericList<int> intList = new GenericList<int>(); intList.Add(1); intList.Add(2); int value = intList.Get(0); GenericList<string> stringList = new GenericList<string>(); stringList.Add("Hello"); stringList.Add("World"); string str = stringList.Get(1);
Platform Compatibility: .NET Core is cross-platform, running on Windows, macOS, and Linux, while .NET Framework is designed for Windows.
Performance: .NET Core generally offers better performance and scalability due to its modular architecture.
Deployment: .NET Core supports side-by-side versioning, allowing multiple versions to coexist. .NET Framework does not support this feature.
Open Source: .NET Core is open-source with community contributions, while .NET Framework is maintained by Microsoft.
API and Libraries: .NET Core and .NET Framework share many APIs, but each has unique ones. .NET Core is more modular.
Use Cases: .NET Core is ideal for modern, scalable applications, while .NET Framework suits existing enterprise applications integrated with Windows.
Dependency Injection (DI) is a design pattern that allows a class to receive its dependencies from an external source. This promotes loose coupling and enhances testability and maintainability. In C# .NET, DI can be implemented using constructor injection, property injection, and method injection. Constructor injection is the most common approach.
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(); } } public class Program { public static void Main(string[] args) { IService service = new Service(); Client client = new Client(service); client.Start(); } }
In this example, the Client
class depends on the IService
interface. The dependency is injected via its constructor, promoting loose coupling.
Entity Framework simplifies data access by allowing developers to interact with a database using strongly-typed .NET objects. It supports various database operations such as Create, Read, Update, and Delete (CRUD). To use Entity Framework, you typically follow these steps:
DbContext
.Example:
public class Product { public int ProductId { get; set; } public string Name { get; set; } public decimal Price { get; set; } } public class AppDbContext : DbContext { public DbSet<Product> Products { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer("YourConnectionStringHere"); } } using (var context = new AppDbContext()) { var product = new Product { Name = "Laptop", Price = 999.99M }; context.Products.Add(product); context.SaveChanges(); var products = context.Products.ToList(); var firstProduct = products.First(); firstProduct.Price = 899.99M; context.SaveChanges(); context.Products.Remove(firstProduct); context.SaveChanges(); }
Microservices architecture is a design approach where an application is built as a collection of loosely coupled, independently deployable services. Each service is responsible for a specific business capability and can be developed, deployed, and scaled independently.
In a .NET environment, microservices can be implemented using ASP.NET Core. Each microservice can be a separate ASP.NET Core project, and they can communicate with each other using HTTP APIs, gRPC, or messaging queues like RabbitMQ.
Example:
[ApiController] [Route("api/[controller]")] public class ProductService : ControllerBase { [HttpGet("{id}")] public IActionResult GetProduct(int id) { return Ok(new { Id = id, Name = "Sample Product" }); } } [ApiController] [Route("api/[controller]")] public class OrderService : ControllerBase { private readonly HttpClient _httpClient; public OrderService(HttpClient httpClient) { _httpClient = httpClient; } [HttpPost] public async Task<IActionResult> CreateOrder(Order order) { var product = await _httpClient.GetStringAsync($"http://productservice/api/product/{order.ProductId}"); return Ok(new { OrderId = 1, Product = product }); } }
In this example, ProductService
and OrderService
are two separate microservices. OrderService
communicates with ProductService
via an HTTP API.
Optimizing the performance of a C# .NET application involves several strategies:
Dictionary
for fast lookups.Design patterns offer solutions to recurring problems, enhance code reusability, and improve the overall architecture of the system. They also facilitate better communication among developers and make the codebase more understandable and maintainable.
One commonly used design pattern in .NET is the Singleton pattern. It ensures that a class has only one instance and provides a global point of access to it. This is useful for managing shared resources, such as configuration settings or database connections.
Example:
public class Singleton { private static Singleton _instance; private static readonly object _lock = new object(); private Singleton() { } public static Singleton Instance { get { lock (_lock) { if (_instance == null) { _instance = new Singleton(); } return _instance; } } } }
In C# .NET, there are several popular testing frameworks for unit testing, including NUnit, MSTest, and xUnit. Each framework has its own features, but they all help developers write and run unit tests to ensure their code behaves as expected.
NUnit is widely used in the .NET ecosystem, providing a rich set of assertions and attributes. MSTest is the default testing framework provided by Microsoft, integrated with Visual Studio. xUnit is known for its extensibility and support for modern testing practices.
Example using NUnit:
using NUnit.Framework; namespace UnitTestExample { public class Calculator { public int Add(int a, int b) { return a + b; } } [TestFixture] public class CalculatorTests { private Calculator _calculator; [SetUp] public void Setup() { _calculator = new Calculator(); } [Test] public void Add_WhenCalled_ReturnsSumOfArguments() { var result = _calculator.Add(2, 3); Assert.AreEqual(5, result); } } }
In this example, we define a simple Calculator
class with an Add
method. We then create a test class CalculatorTests
with a test method Add_WhenCalled_ReturnsSumOfArguments
that verifies the Add
method returns the correct sum.
Building RESTful services in C# .NET typically involves using ASP.NET Core, a framework that provides a robust environment for creating web APIs. To build a RESTful service, you define controllers and actions that correspond to HTTP methods like GET, POST, PUT, and DELETE.
Example of building a RESTful service:
using Microsoft.AspNetCore.Mvc; [ApiController] [Route("api/[controller]")] public class ProductsController : ControllerBase { [HttpGet] public IActionResult GetAllProducts() { var products = new List<string> { "Product1", "Product2" }; return Ok(products); } [HttpPost] public IActionResult CreateProduct([FromBody] string product) { return CreatedAtAction(nameof(GetAllProducts), new { id = 1 }, product); } }
To consume a RESTful service, you can use the HttpClient class in C#. This class provides methods to send HTTP requests and receive HTTP responses from a resource identified by a URI.
Example of consuming a RESTful service:
using System.Net.Http; using System.Threading.Tasks; public class ProductService { private readonly HttpClient _httpClient; public ProductService(HttpClient httpClient) { _httpClient = httpClient; } public async Task<string> GetProductsAsync() { var response = await _httpClient.GetAsync("https://example.com/api/products"); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); } }