Interview

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.

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.

C# .NET Interview Questions and Answers

1. What are the main components of the .NET framework?

The .NET framework is a software development platform developed by Microsoft. It consists of several key components:

  • Common Language Runtime (CLR): The CLR is the execution engine for .NET applications, providing services such as memory management and exception handling.
  • Base Class Library (BCL): A collection of reusable classes and interfaces offering functionalities like file I/O and data access.
  • Framework Class Library (FCL): Extends the BCL with additional libraries for web development and data access.
  • Common Type System (CTS): Defines how types are declared and managed, ensuring interoperability between .NET languages.
  • Common Language Specification (CLS): A set of rules ensuring interoperability between .NET languages.
  • Assemblies and the Global Assembly Cache (GAC): Assemblies are the building blocks of .NET applications, containing compiled code and resources. The GAC stores shared assemblies for versioning and reuse.
  • ADO.NET: Facilitates data access and manipulation from various data sources.
  • ASP.NET: A framework for building web applications and services.
  • Windows Forms and WPF: Frameworks for building desktop applications, with WPF offering advanced graphics capabilities.

2. Explain how garbage collection works in .NET.

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:

  • Generation 0: Stores short-lived objects, frequently collected by the GC.
  • Generation 1: Acts as a buffer between short-lived and long-lived objects.
  • Generation 2: Contains long-lived objects.

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.

3. Describe how async and await work.

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.

4. How do you subscribe to and raise events?

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.

5. What are assemblies and why are they important?

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:

  • Encapsulation: Assemblies encapsulate code and resources, simplifying management and deployment.
  • Versioning: Assemblies support versioning, allowing multiple versions to coexist.
  • Security: Assemblies include metadata that the CLR uses to enforce security policies.
  • Deployment: Assemblies bundle necessary components into a single unit.

6. Describe how reflection works and provide an example use case.

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.

7. How do you define and use generics?

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);

8. What are the key differences between .NET Core and .NET Framework?

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.

9. How would you implement dependency injection?

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.

10. Describe how to use Entity Framework for database operations.

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:

  • Install Entity Framework via NuGet.
  • Define your model classes.
  • Create a context class that inherits from DbContext.
  • Use LINQ queries to perform database operations.

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();
}

11. What is microservices architecture and how can it be implemented?

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.

12. How would you optimize the performance of an application?

Optimizing the performance of a C# .NET application involves several strategies:

  • Code Optimization: Ensure efficient code by avoiding unnecessary computations and using appropriate algorithms.
  • Efficient Data Structures: Choose the right data structures for the task, such as using a Dictionary for fast lookups.
  • Memory Management: Be mindful of memory usage and avoid memory leaks by properly disposing of objects.
  • Asynchronous Programming: Utilize asynchronous programming to improve responsiveness and scalability.
  • Caching: Implement caching to store frequently accessed data in memory.
  • Parallel Processing: Leverage parallel processing to perform multiple operations concurrently.
  • Profiling and Monitoring: Use profiling tools to identify performance bottlenecks.
  • Database Optimization: Optimize database queries and indexes.
  • Configuration and Deployment: Ensure the application is configured correctly for the production environment.

13. Explain the importance of design patterns and give an example of one commonly used in .NET.

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;
            }
        }
    }
}

14. Which testing frameworks have you used and how do you implement unit tests?

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.

15. How do you build and consume RESTful services?

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();
    }
}
Previous

10 Log Parsing Interview Questions and Answers

Back to Interview
Next

10 Data Processing Interview Questions and Answers