DEV Community

Cover image for 20 C# Interview Questions (for Freshers) 2023
ByteHide
ByteHide

Posted on • Originally published at bytehide.com

20 C# Interview Questions (for Freshers) 2023

Hey there, fellow C# enthusiasts! So you've mastered the basics and now you're eager to tackle some more challenging interview questions, huh? Maybe you're a fresher looking to make a strong impression at your first interview or simply looking to build up your C# know-how. Guess what? You've come to the right place, my friend!

In this article, we'll dive into 20 C# interview questions perfect for freshers; ones that are a notch above the basics but still totally doable. Thrown in the mix, you'll find a blend of questions to test your logical thinking, code analysis skills and those ever-so-important programming concepts.

Ready to knock the socks off your interviewers?

Let's roll!

What is a namespace in C#?

Answer

A namespace in C# is a way to group related types and improve the organization of your code. It is used to avoid naming conflicts between different classes or types that may have the same identifier. Namespaces work as a hierarchy, where you can have nested namespaces, and they can span multiple files or even libraries.

For example:

namespace Company.Project
{
    class MyClass
    {
        // Class implementation
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, the MyClass class is declared inside the Company.Project namespace.

What is the purpose of the ‘using’ directive in C#?

Answer

The using directive in C# has two primary purposes:

  • Namespace importing: using allows you to import a namespace so that you can use the types and members defined in that namespace without specifying their fully qualified name. It makes your code more readable and reduces code complexity. For example:
using System;

    class Program
    {
        static void Main()
        {
            // Without the 'using' directive, you would need to write: System.Console.WriteLine("Hello, World!");
            Console.WriteLine("Hello, World!");
        }
    }
Enter fullscreen mode Exit fullscreen mode
  • Resource management: The using statement is used to help you manage resources like file streams, network connections, or database connections that implement the IDisposable interface. The using statement ensures that the Dispose() method is called on the resource when the block of code is exited, releasing the resources properly. For example:
using System.IO;

    class Program
    {
        static void Main()
        {
            using (StreamReader reader = new StreamReader("file.txt"))
            {
                // Code to read from the file
            } // At this point, the Dispose() method of the StreamReader is automatically called, releasing resources.
        }
    }
Enter fullscreen mode Exit fullscreen mode

What are reference types in C#?

Answer

Reference types in C# are types that store a reference to the memory location where the data is stored, rather than the actual data itself. When you create objects from classes or use arrays, delegates, interfaces, or most built-in data structures from the .NET Framework, you are working with reference types. Unlike value types, reference types are allocated on the heap, and the garbage collector manages their memory.

Key aspects of reference types:

  • When you pass a reference type as a method parameter or assign it to another variable, both variables will refer to the same memory location. Thus, modifications in one variable will affect the other one.
  • Reference types can have a null value, which means they don’t reference any memory location or object.
class Person
{
    public string Name { get; set; }
}

Person person1 = new Person { Name = "John" };
Person person2 = person1; // Both person1 and person2 reference the same object in memory
person2.Name = "Jane"; // Changing person2.Name also updates person1.Name, as they both refer to the same object
Enter fullscreen mode Exit fullscreen mode

How do you declare a method in C#?

Answer

A method in C# is a block of code that performs a specific task and can be called as many times as needed. To declare a method, you need to specify its access level, return type, method name, and a parameter list (if applicable) within the class. Here’s an example:

public class Calculator
{
    public int Add(int a, int b)
    {
        int sum = a + b;
        return sum;
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, we declare a method named Add with the public access modifier, an int return type, and two parameters of type int. The method calculates the sum of the two numbers and returns the result.

What are the basic access modifiers available in C#?

Answer

Access modifiers in C# control the visibility and accessibility of class members (methods, properties, fields, etc.) and classes themselves. The basic access modifiers available in C# are:

  1. public: Members and classes with the public access modifier are accessible from any code inside the same assembly or another assembly that references it.
  2. private: Members declared as private can only be accessed within the same class. They are not visible to other classes, even within the same assembly. By default, class members are private if no access modifier is specified.
  3. protected: Members declared with the protected access modifier can be accessed within the same class, as well as within derived classes. They are not visible to other non-derived classes in the same assembly.
  4. internal: Members and classes with the internal access modifier can be accessed anywhere within the same assembly but are not visible to other assemblies.
  5. protected internal: Members declared with the protected internal access modifier are accessible within the same assembly and by derived classes in another assembly.
public class MyClass
{
    public int PublicMember;
    private int PrivateMember;
    protected int ProtectedMember;
    internal int InternalMember;
    protected internal int ProtectedInternalMember;
}
Enter fullscreen mode Exit fullscreen mode

What is a constructor in C#?

Answer

A constructor is a special method in a class that is called when an object of that class is created. Constructors have the same name as the class and don’t have an explicit return type. Constructors can be overloaded, which means you can have multiple constructors within a class with different parameter lists.

Constructors are used to:

  • Initialize the object’s state (set default values for properties, fields, etc.).
  • Allocate resources, such as memory or network connections.
  • Verify input parameters or ensure that the object is in a consistent state.

Example:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    // Default constructor
    public Person()
    {
        Name = "Unknown";
        Age = 0;
    }

    // Parameterized constructor
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

// Usage:
Person person1 = new Person(); // Calls the default constructor
Person person2 = new Person("John", 25); // Calls the parameterized constructor
Enter fullscreen mode Exit fullscreen mode

What are indexers in C#?

Answer

Indexers in C# are class members that allow you to access an object’s elements using index notation, similar to how you access elements in an array or a collection. Indexers provide a more intuitive way to interact with the elements stored in a class, especially when it contains a collection or an array.

To define an indexer, you need to use the this keyword, the type of the elements you want to access, and implement the get and set accessors to access and modify the underlying elements.

Here’s an example of an indexer implementation for a simple custom collection class:

public class MyCollection
{
    private int[] items = new int[10];

    public int this[int index]
    {
        get
        {
            return items[index];
        }
        set
        {
            items[index] = value;
        }
    }
}

// Usage:
MyCollection collection = new MyCollection();
collection[0] = 42; // Uses the indexer's set accessor
int firstItem = collection[0]; // Uses the indexer's get accessor
Enter fullscreen mode Exit fullscreen mode

How do you create custom exception handling in C#?

Answer

To create custom exception handling in C#, you can create a custom exception class that inherits from the built-in System.Exception class or one of its derived classes. Custom exceptions are useful when the built-in exception classes don’t cover specific error situations in your application.

Here’s an example of a custom exception class:

public class CustomException : Exception
{
    public CustomException() : base()
    {
    }

    public CustomException(string message) : base(message)
    {
    }

    public CustomException(string message, Exception innerException) : base(message, innerException)
    {
    }
}
Enter fullscreen mode Exit fullscreen mode

Now you can throw and catch the CustomException in your code:

try
{
    // Some code that might throw a CustomException
    throw new CustomException("This is a custom exception");
}
catch (CustomException ex)
{
    Console.WriteLine("Caught a CustomException: " + ex.Message);
}
Enter fullscreen mode Exit fullscreen mode

How can you prevent class inheritance in C#?

Answer

To prevent class inheritance in C#, you can use the sealed keyword when declaring the class. A sealed class cannot be inherited by any other class, and it is a compile-time error to try to inherit from a sealed class.

public sealed class NonInheritableClass
{
    // Class implementation
}

// This will result in a compile-time error:
public class MyClass : NonInheritableClass
{
}
Enter fullscreen mode Exit fullscreen mode

What is the difference between ‘const’ and ‘readonly’ in C#?

Answer

const and readonly are both used in C# to create variables that cannot be changed after they are assigned a value, but they have some differences:

  • const:
  • Can only be applied to fields, not properties.
  • Must be assigned a value at declaration.
  • The value assigned must be a constant expression that can be resolved at compile-time.
  • const fields are implicitly static, and you cannot use instance members to initialize them.
public class Constants
{
    public const double Pi = 3.14159;
}
Enter fullscreen mode Exit fullscreen mode
  • readonly:
  • Can be applied to fields and properties.
  • Can be assigned a value at declaration or inside a constructor.
  • The value assigned can be a constant expression or a non-constant expression that is resolved at runtime.
  • readonly fields can be either static or instance members, depending on your needs.
public class ReadOnlyFields
{
    public readonly int InstanceField;
    public static readonly int StaticField;

    public ReadOnlyFields(int instanceValue, int staticValue)
    {
        InstanceField = instanceValue;
        StaticField = staticValue;
    }
}
Enter fullscreen mode Exit fullscreen mode

Summary of differences:

  • const is a compile-time constant, and its value cannot depend on runtime conditions. readonly is a runtime constant, and its value can be determined at runtime.
  • const fields are implicitly static, while readonly fields can be either static or instance members.

What is garbage collection in C#?

Answer

Garbage collection (GC) in C# is an automatic memory management system provided by the .NET Framework. It is responsible for freeing up memory that is no longer being used by the application. The garbage collector keeps track of objects allocated on the heap, determines which objects are no longer accessible, and reclaims the corresponding memory space.

The main benefits of garbage collection are:

  • Improved developer productivity by reducing boilerplate code for manual memory management.
  • Prevention of memory leaks, as unused memory gets automatically reclaimed.
  • Protection against certain programming bugs, like dangling pointers or double-free issues.

C#’s garbage collection is non-deterministic, meaning that you cannot predict when exactly the garbage collector will run. It uses a generational approach, classifying objects into generations to reduce the time and resources spent on garbage collection. The garbage collector will typically run when available memory is getting low or when the system is idle.

While garbage collection can bring benefits, care should still be taken when dealing with heavy resource-consuming objects, like file handlers or database connections. Classes that deal with such resource management should implement the IDisposable interface to allow deterministic resource release.

Describe object-oriented programming (OOP) in C#. Name the main OOP concepts.

Answer

Object-Oriented Programming (OOP) is a programming paradigm that represents concepts as objects with attributes (fields or properties) and behaviors (methods). The goal of OOP is to produce reusable, maintainable, and modular code by emphasizing the separation of concerns and adhering to OOP principles.

C# is an object-oriented programming language, and it fully supports OOP concepts. The main OOP concepts in C# are:

  1. Encapsulation: The process of bundling data (attributes) and methods (functions) that operate on the data into a single unit (class). Encapsulation helps to protect the internal state of an object and control access to its attributes.
  2. Inheritance: The ability of a class to inherit properties, methods, and behaviors from another class (base class) to enable code reuse and represent a hierarchy of related objects. In C#, a class can only inherit from a single class but can implement multiple interfaces.
  3. Polymorphism: Polymorphism is the ability of a single interface to represent different types or the ability of a method to have multiple implementations based on derived types. In C#, polymorphism can be achieved through overloading (using the same method name with different parameters in the same type) and overriding (redefining a base class method in a derived class).
  4. Abstraction: Abstraction is the process of simplifying complex real-world objects and concepts by focusing on their essential features. Abstraction can be achieved in C# by using abstract classes and interfaces to define the common properties and methods that a group of related types must implement.

How can you create a generic class or method in C#?

Answer

A generic class or method in C# is a class or method that can work with any type without the need for explicit type casting or type checking at runtime. Generic types increase the reusability, flexibility, and type safety of your code.

To create a generic class or method in C#, you need to use the angle brackets <T> to define a type parameter. Here’s an example of a generic class and a generic method:

// A generic class example
public class GenericList<T>
{
    // Class implementation using the generic type parameter T
}

// A generic method example
public static T Max<T>(T value1, T value2) where T : IComparable<T>
{
    return value1.CompareTo(value2) > 0 ? value1 : value2;
}
Enter fullscreen mode Exit fullscreen mode

In this example, T is the type parameter for both the generic class GenericList<T> and the generic method Max<T>(T, T). The method also uses a constraint (where T : IComparable<T>) to ensure that the type parameter T implements the IComparable<T> interface.

What is the difference between an abstract class and an interface in C#?

Answer

Both abstract classes and interfaces are used to define abstract entities in C#, but they have some differences:

Abstract Class:

  • Can have both abstract and non-abstract (implemented) methods.
  • Can have fields (variables), properties, and events.
  • Supports constructors and destructors.
  • Can have access modifiers for members (public, protected, internal, etc.).
  • Supports inheritance; a class can inherit from only one abstract class.
  • Can have complete implementations for some methods or properties, but cannot be instantiated directly.

Interface:

  • Can only have method, property, and event signatures (no implementation).
  • Cannot have fields or constructors.
  • No member (methods, properties, events) can have an access modifier (all are implicitly public).
  • Supports multiple inheritance; a class can implement multiple interfaces.
  • Cannot have any implementation details, just the signatures of the members.

In summary, abstract classes provide a base implementation that can be shared among multiple derived classes, while interfaces define a contract that any implementing class must adhere to. Use an abstract class when you want to provide some default behavior and an interface when you need multiple inheritance or want to strictly define a common functionality contract.

What is the difference between ‘out’ and ‘ref’ parameters in C#?

Answer

Both out and ref parameters in C# are used to pass arguments by reference, allowing a method to modify the values of the passed variables outside the method. However, there are some differences between the two:

ref:

  • The variable passed as a ref parameter must be initialized before passing it to the method.
  • The method called doesn’t have to assign a value to the ref parameter, as it already has a value. Example:
  public void Swap(ref int a, ref int b)
  {
      int temp = a;
      a = b;
      b = temp;
  }

  int x = 1, y = 2;
  Swap(ref x, ref y); // x = 2, y = 1 after the method call
Enter fullscreen mode Exit fullscreen mode

out:

  • The variable passed as an out parameter doesn’t need to be initialized before passing it to the method.
  • The method called must assign a value to the out parameter before the method returns. Example:
  public void Divide(int a, int b, out int quotient, out int remainder)
  {
      quotient = a / b;
      remainder = a % b;
  }

  int q, r;
  Divide(10, 3, out q, out r); // q = 3, r = 1 after the method call
Enter fullscreen mode Exit fullscreen mode

In summary, use ref parameters when you want the called method to modify an already initialized variable, and use out parameters when you want the called method to provide a value that doesn’t depend on the initial value of the passed variable.

Describe the concept of delegates in C#.

Answer

A delegate in C# is a reference type that represents a method with a specific signature. Delegates allow you to treat methods as objects and pass them as arguments, return them from methods, or store them as properties. Delegates provide a way to create function pointers or callbacks, making it possible to develop more flexible and extensible applications.

Delegates are particularly useful when designing event-driven systems, where components must react to other component events or signals without tight coupling. Here’s an example of a delegate declaration, instantiation, and invocation:

// Declare a delegate type with a specific signature
public delegate void MyDelegate(string message);

// A method that matches the delegate signature
public static void Greet(string message)
{
    Console.WriteLine("Hello, " + message);
}

// Create an instance of the delegate, assigning the method to it
MyDelegate greetDelegate = new MyDelegate(Greet);

// Invoke the delegate
greetDelegate("World");
Enter fullscreen mode Exit fullscreen mode

C# also supports generic delegates, multicast delegates, and built-in Func<T, TResult> and Action<T> delegates (introduced in .NET Framework 3.5) for increased flexibility and usability.

What is the difference between the ‘==’, ‘Equals’, and ‘ReferenceEquals’ methods?

Answer

In C#, ‘==’, ‘Equals’, and ‘ReferenceEquals’ are used to compare objects or values for equality, but with some differences:

  1. == operator: The ‘==’ operator compares two objects or values for equality. For value types, it checks if the values are equal. For reference types, it checks if the object references are equal, which means they’re pointing to the same object in memory. This behavior can be overridden for custom reference types by overloading the ‘==’ operator.
   int a = 10;
   int b = 10;
   Console.WriteLine(a == b); // True, because the values are equal

   string s1 = "hello";
   string s2 = new String("hello".ToCharArray());
   Console.WriteLine(s1 == s2); // False, because the object references are different
Enter fullscreen mode Exit fullscreen mode
  1. Equals: The ‘Equals’ method compares two objects for equality by checking their values, not their references. The default implementation of ‘Equals’ for reference types checks reference equality, but it can be overridden in your custom class to provide value-based comparison.
   string s1 = "hello";
   string s2 = new String("hello".ToCharArray());
   Console.WriteLine(s1.Equals(s2)); // True, because the values are equal
Enter fullscreen mode Exit fullscreen mode
  1. ReferenceEquals: The ‘ReferenceEquals’ method checks if two object references are equal, meaning they point to the same object in memory. It does not compare values. This method cannot be overridden and is useful when you need to perform a strict reference comparison.
   string s1 = "hello";
   string s2 = new String("hello".ToCharArray());
   Console.WriteLine(ReferenceEquals(s1, s2)); // False, because the object references are different
Enter fullscreen mode Exit fullscreen mode

In summary, use the ‘==’ operator for simple value comparisons and reference comparisons, ‘Equals’ when you need to perform a value-based comparison for reference types, and ‘ReferenceEquals’ when you want to specifically compare object references.

Explain the concept of dependency injection in C#.

Answer

Dependency Injection (DI) is a design pattern used in C# and other object-oriented languages that helps to separate the creation and management of object dependencies, increasing the modularity, maintainability, and testability of an application.

In the context of C#, dependency injection is a technique in which an object receives its dependencies (objects, services, or values it relies on) from an external source instead of directly creating, managing, or looking up these dependencies. Dependency injection can be achieved using constructor injection, property injection, or method injection:

  1. Constructor Injection: The dependencies are passed to the object through its constructor. This is the most common and recommended method of dependency injection because it enforces that the object is created with all required dependencies and in a valid state.
   public class UserService
   {
       private readonly ILogger _logger;

       public UserService(ILogger logger)
       {
           _logger = logger;
       }

       public void DoSomething()
       {
           _logger.Log("User Service is doing something.");
       }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Property Injection: The dependencies are set through public properties or setters of an object. This technique is used when the dependency is optional or can be changed during object lifetime.
   public class UserService
   {
       public ILogger Logger { get; set; }

       public void DoSomething()
       {
           Logger?.Log("User Service is doing something.");
       }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Method Injection: The dependencies are passed to an object through a method. This technique is suitable when an object requires a specific dependency for just one method and not for the entire lifecycle of the object.
   public class UserService
   {
       public void DoSomething(ILogger logger)
       {
           logger.Log("User Service is doing something.");
       }
   }
Enter fullscreen mode Exit fullscreen mode

In C#, popular dependency injection frameworks like Autofac, Unity, or built-in .NET Core Dependency Injection can be used to manage and resolve object dependencies.

How does C# support multiple inheritances?

Answer

C# does not directly support multiple inheritance for classes. A class in C# can inherit from only one base class. However, C# allows multiple inheritance through interfaces, as a class can implement multiple interfaces.

When a class implements multiple interfaces, it essentially inherits the behavior of each interface, and each interface can be considered as a contract that the class must adhere to. This approach to multiple inheritance enables flexibility while avoiding the complexity and ambiguity that can arise from multiple class inheritance.

Example:

public interface IEngine
{
    void StartEngine();
}

public interface IDriver
{
    void Drive();
}

public class Car : IEngine, IDriver
{
    public void StartEngine()
    {
        Console.WriteLine("Car engine started.");
    }

    public void Drive()
    {
        Console.WriteLine("Car is being driven.");
    }
}

// Usage:
Car car = new Car();
car.StartEngine();
car.Drive();
Enter fullscreen mode Exit fullscreen mode

In this example, Car implements the IEngine and IDriver interfaces to provide multiple inheritance-like functionality.

What is method overloading in C#?

Answer

Method overloading is a feature in C# that allows a class to have multiple methods with the same name, but different parameter lists. The correct method is called at compile time based on the arguments provided. Method overloading is a way to achieve compile-time polymorphism. The return type of the methods doesn’t factor into overloading. The method signature, i.e., the method name and parameter list, must be unique.

Here’s an example:

public class Calculator
{
    public int Add(int x, int y)
    {
        return x + y;
    }

    public double Add(double x, double y)
    {
        return x + y;
    }

    public int Add(int x, int y, int z)
    {
        return x + y + z;
    }
}
Enter fullscreen mode Exit fullscreen mode

In the example above, we’ve overloaded the Add method with different parameter lists.

That's it, folks! These 20 for freshers C# questions are just the beginning.

Stick with me, as I'll be sharing more C# interview questions, tailored for all skill levels - from total newbies to seasoned pros.

Don't forget to follow, so you're always in the loop. Let's ace C# together!

Keep on coding, my friends!

Latest comments (3)

Collapse
 
marqitos profile image
Marcos Porto Mariño

Now interfaces can have static methods. I use them as if they were extension methods, when it is some functionality that I end up using in most implementations, or simply together.

Collapse
 
ant_f_dev profile image
Anthony Fung

Very cool.

In newer versions of C#, you can use file-scope namespacing too, e.g.

namespace Company.Project;

class MyClass
{
    // Class implementation
}
Enter fullscreen mode Exit fullscreen mode

This means everything in the file is in the same namespace and is quite useful to reduce nesting by one layer (if everything indeed should be in the same namespace)

Collapse
 
bytehide profile image
ByteHide

Absolutely, Anthony! The new feature in C# 10 allows you to use file-scope namespaces. It's simpler and makes code cleaner by reducing extra layers. A great tip for better-looking code. Thanks for sharing!