Popular C# coding questions to prep for a technical interview

Published: Monday 6 May 2024

When applying for a .NET or C# developer role, you'll likely to be asked a number of technical interview questions.

Popular technical interview questions

Here are some of the most popular questions that hiring managers like to ask:

What is an interface?

An interface defines a contract. Any class, record or struct that implements the interface must provide an implementation of the members defined within it.

Members that can be added to an interface include methods and properties and these can have default implementations added to it.

An interface can not be initialised as it can't contain a non-static constructor. It would be the class, record or struct that is implementing the interface that would be initialised.

In this example, we have created an IProduct interface which contains read only properties for the product, including the name, price and whether it's taxable. We've also included a method to calculate the price based on the currency.

The Product class implements the IProduct interface and has included all the properties and methods, including how the price is calculated based on the currency.

// IProduct.cs
public interface IProduct
{
	string Name { get; }

	decimal? Price { get; }

	bool Taxable { get => true; }

	decimal? GetPrice(string currency);
}
// Product.cs
public class Product : IProduct
{
	public string Name { get; }

	public decimal? Price { get; }

	public bool Taxable { get; }

	public decimal? GetPrice(string currency)
	{
		return currency switch
		{
			"USD" => Price,
			"GBP" => Price / 0.8m,
			_ => null
		};
	}

	public Product(string name, decimal? price, bool taxable)
	{
		Name = name;
		Price = price;
		Taxable = taxable;
	}
}

What is an abstract class?

An abstract class is class that can't be initialised directly. A child class that is non-abstract and is inheriting the abstract parent class is responsible for the initialisation.

As well as the abstract keyword on a class, it can also be used with methods and properties. The purpose of it is to provide a common definition that inherited child classes must define.

An abstract class can have a mixture of abstract and non-abstract members within it.

In this example, we have created a ProductBase abstract class that implements the IProduct interface. As it implements the IProduct interface, it must include all the members from it.

The GetPrice method as been marked as abstract. As a result, it doesn't include a body as this will be overridden and defined in any classes that are inheriting it.

The ProductBase abstract class also has a constructor with two parameters defined. This can be used with any classes that are implementing the class.

Then we have modified the Product class to inherit the ProductBase abstract class. We have created a constructor defining two properties, and this calls the constructor in the ProductBase abstract class using the base keyword.

Because the GetPrice method as been marked as abstract, we need to override it and define the logic in the method.

// IProduct.cs
public interface IProduct
{
	string Name { get; }

	decimal? Price { get; }

	bool Taxable { get => true; }

	decimal? GetPrice(string currency);
}
// ProductBase.cs
public abstract class ProductBase : IProduct
{
	public string Name { get; }

	public decimal? Price { get; }

	public bool Taxable { get; }

	public abstract decimal? GetPrice(string currency);

	protected ProductBase(string name, decimal? price, bool taxable)
	{
		Name = name;
		Price = price;
		Taxable = taxable;
	}
}
// Product.cs
public class Product : ProductBase
{
	public Product(string name, decimal? price, bool taxable) : base(name, price, taxable)
	{
	}

	public override decimal? GetPrice(string currency)
	{
		return currency switch
		{
			"USD" => Price,
			"GBP" => Price / 0.8m,
			_ => null
		};
	}
}

Can you have multiple implementations of interfaces in the same class?

Yes you can have multiple implementations of interfaces in the same class.

In this example, we've moved the Taxable property from the IProduct interface into it's own IProductTax interface and implemented it as part of the ProductBase class.

As long as we remember to define all members from both interfaces in the ProductBase class, the code will still compile.

// IProduct.cs
public interface IProduct
{
	string Name { get; }

	decimal? Price { get; }

	decimal? GetPrice(string currency);
}
// IProductTax.cs
public interface IProductTax
{
	bool Taxable { get => true; }
}
// ProductBase.cs
public abstract class ProductBase : IProduct, IProductTax
{
	public string Name { get; }

	public decimal? Price { get; }

	public bool Taxable { get; }

	public abstract decimal? GetPrice(string currency);

	protected ProductBase(string name, decimal? price, bool taxable)
	{
		Name = name;
		Price = price;
		Taxable = taxable;
	}
}
// Product.cs
public class Product : ProductBase
{
	public Product(string name, decimal? price, bool taxable) : base(name, price, taxable)
	{
	}

	public override decimal? GetPrice(string currency)
	{
		return currency switch
		{
			"USD" => Price,
			"GBP" => Price / 0.8m,
			_ => null
		};
	}
}

Can you have multiple class inheritances in the same class?

No, you are not able to have multiple class inheritances in the same class. Each class can only have one class inheritance.

However, you can have multi level inheritance where one class inherits another class, and that class inherits another class.

In this example, we have created a new BookProduct class which adds an ISBN property to the product.

This class has multi level inheritance as it inherits the Product class which in turn inherits the ProductBase class.

// ProductBase.cs
public abstract class ProductBase : IProduct, IProductTax
{
	public string Name { get; }

	public decimal? Price { get; }

	public bool Taxable { get; }

	public abstract decimal? GetPrice(string currency);

	protected ProductBase(string name, decimal? price, bool taxable)
	{
		Name = name;
		Price = price;
		Taxable = taxable;
	}
}
// Product.cs
public class Product : ProductBase
{
	public Product(string name, decimal? price, bool taxable) : base(name, price, taxable)
	{
	}

	public override decimal? GetPrice(string currency)
	{
		return currency switch
		{
			"USD" => Price,
			"GBP" => Price / 0.8m,
			_ => null
		};
	}
}
// BookProduct.cs
public class BookProduct : Product
{
	public string ISBN { get; }

	public BookProduct(string name, decimal? price, bool taxable, string isbn) : base(name, price, taxable)
	{
		ISBN = isbn;
	}
}

What is the virtual method?

Defining a virtual method is a method that can be overridden in a derived class. The virtual reference can also be used in properties as well as events and indexers.

In this example, we have created a new GetShippingCost method in the Product class which has been marked with the virtual reference.

This has been overridden in the BookProduct class which inherits the Product class to include it's own shipping costs. This is done using the override keyword.

// Product.cs
public class Product : ProductBase
{
	public Product(string name, decimal? price, bool taxable) : base(name, price, taxable)
	{
	}

	public override decimal? GetPrice(string currency)
	{
		return currency switch
		{
			"USD" => Price,
			"GBP" => Price / 0.8m,
			_ => null
		};
	}

	public virtual decimal? GetShippingCost()
	{
		return Price switch
		{
			>= 50 => 0,
			_ => 5
		};
	}
}
// BookProduct.cs
public class BookProduct : Product
{
	public string ISBN { get; }

	public BookProduct(string name, decimal? price, bool taxable, string isbn) : base(name, price, taxable)
	{
		ISBN = isbn;
	}

	public override decimal? GetShippingCost()
	{
		return Price switch
		{
			>= 30 => 0,
			_ => 5
		};
	}
}

What is method overloading?

Method overloading is when you include two or more methods of the same name. The difference with each method is the number or types of parameters included in that method.

In this example, we've added another GetShippingCost method to the BookProduct class. This takes a specialOffer parameter which when true will offer a different shipping cost. If it's set to false, it will use the return value from the parameterless GetShippingCost method.

// Product.cs
public class Product : ProductBase
{
	public Product(string name, decimal? price, bool taxable) : base(name, price, taxable)
	{
	}

	public override decimal? GetPrice(string currency)
	{
		return currency switch
		{
			"USD" => Price,
			"GBP" => Price / 0.8m,
			_ => null
		};
	}

	public virtual decimal? GetShippingCost()
	{
		return Price switch
		{
			>= 50 => 0,
			_ => 5
		};
	}
}
// BookProduct.cs
public class BookProduct : Product
{
	public string ISBN { get; }

	public BookProduct(string name, decimal? price, bool taxable, string isbn) : base(name, price, taxable)
	{
		ISBN = isbn;
	}

	public override decimal? GetShippingCost()
	{
		return Price switch
		{
			>= 30 => 0,
			_ => 5
		};
	}

	public decimal? GetShippingCost(bool specialOffer)
	{
		if (specialOffer)
		{
			return Price switch
			{
				>= 20 => 0,
				_ => 5
			};
		}
		return GetShippingCost();
	}
}

What are the access modifiers?

Access modifiers can be used to determine the access level for classes, structs and interfaces. It can also be used for members within these, such as methods and properties.

These are the different ones that can be used in C#:

  • public - Can be accessed by any code
  • private - Can only be accessed by code in the same class or struct
  • protected - Can only be accessed by code in the same or derived class
  • internal - Can only be accessed by code in the same assembly
  • protected internal - Can only be accessed in the same assembly, or in a derived class from another assembly
  • private protected - Can only be accessed in the same assembly, and in the same or derived class
  • file - Can only be accessed in the same file

Other technical assessments

As well as being asked technical questions, you may have other technical assessments as part of the interview process. These include:

  • Take-home code challenge - This is where the hiring manager will set you a task to complete in your own time. An example of this is to create an ASP.NET Core Web API with endpoints, unit tests and a full commit history
  • Pair programming - This is where you will virtually connect with a technical member of the interview team through a video call. They will set you an assignment and they can you watch you implement the solution whilst you're doing it. They will normally be on hand to answer any questions you may have and point you in the right direction
  • Timed coding challenge - This is an automated coding challenge where you have a limited amount of time to implement the solution. There are many online coding challenges that allow you to practice for this, including our coding challenges

Offer stage

Should you be successful in completing your technical assessment, you will hopefully receive an offer. The amount they propose will likely be based off the salary expectations you gave to the recruiter at the start of the process.

If it's slightly lower than you were hoping, see if there is any room for improvement. But don't feel pressured to accept it. If the offer is much lower than you were hoping, be prepared to walk away particularly if you are currently employed.

If you are happy with it and you're not currently working, accept it and agree on a start date with the recruiter.

Handing in your notice

However if you are still employed, you'll have to hand in your notice to your current employer. Your current employer is likely to be shocked that you are suddenly leaving. If you are a top performer within the company, they will do all that they can to try and keep you.

One of their tricks is to give you a counter offer where they will improve your current job situation, such as:

  • An increase on your current salary that matches or even exceeds what your potential new employer is offering
  • A one off bonus
  • A promotion with a better job title and more responsibilities

They may offer you some, or all of these.

In-addition, your current employer is likely to be very persuasive as to why you should stay with them and may give you excess praise.

However, think very carefully when accepting a counter offer. Ask yourself why they are offering this now? Why was this not offered six months ago?

The likelihood is for their benefit to buy them some time in trying to find a replacement for you. You are no longer loyal to the company and they can no longer trust you to stay in your position long term.

You could also end up on the redundancy list if there is a need for layoffs in the near future.

Watch our video

Watch our video where we go through the different C# technical interview questions and provide answers and explanations on how they work.

The SOLID principles

One more popular C# technical interview question that hiring managers like to ask is asking you what the SOLID principles are.

Read our article on the SOLID principles used in C# to familiarise yourself with each one and how you can use them in your project.