11 Important C# Interview Questions & OOP Concepts

Published Nov 07, 2016Last updated Feb 21, 2017
11 Important C# Interview Questions & OOP Concepts

Introduction

C# has grown into a formidable programming language and one that is not only in high demand worldwide, but also one that is versatile and cross-platform.

Today, it is possible to write C# code not only on Windows systems but also on Mac and *NIX (Linux & UNIX) distributions, thanks to open source initiatives such as .NET Core, ASP.NET Core, and Xamarin.

There hasn’t been a more exciting time to be a C# developer than today! Having this said, it is particularly important to not only be fluent in the language to land a job but also to have a good understanding of the technology landscape that specifically caters to C# and it’s community, in order to stand out from the crowd.

It is also extremely important to understand what the language was originally designed for and make the most of it.

The goal of this tutorial is to broaden your view on not only how the C# language is applied on certain problem-solving scenarios, but also how it fits in today’s constant evolving technological landscape and how you as a developer must be aware of these implications. The overall objective is to be able to not only use it but apply it in specific cases where it is the best tool to carry out the task at hand.


Want to ace your technical interview? Schedule a Technical Interview Practice Session with an expert now!


Scope and Limitations

The concepts that will be explained in this article are mostly applicable for both junior and senior developers; however, they could be particularly interesting for junior developers that aspire to become more senior in their current roles and get a much better understanding of Object Orientation as they advance their career.

It is important to notice that there’s no guarantee that the type of questions and content that will be explained here would appear in a technical interview; however, it is meant to expand your horizon as a developer and see things from the point of the person carrying out the interview, especially if you are being evaluated about Object Orientation.

Sounds exciting—so let’s see what we can learn. Enjoy!

Read more: Comparing Programming Paradigms: Procedural Programming vs Object-oriented Programming

C# Interview Questions & OOP Concepts

Setting the Stage: C# and OO

C# is one of those programming languages that was developed with Object Orientation (OO) in mind, however, most developers don’t fully exploit OO.

When writing code, it resembles actual procedural and structured programming constructs wrapped up into classes, rather than fundamental OO.

Question 1: So what makes your code really object-oriented?

In order to understand this, we must first analyze what benefits we can derive from OO. In order to do this, we must clearly understand its foundation.

So given that C# is at its core object-oriented, most interviewers might be tempted to ask the following question:

Question 2: What are the fundamental principles of OO programming?

As a developer, you might be tempted to answer that it comprises things like Encapsulation, Polymorphism, Abstraction, and Inheritance. Although this is true, it doesn’t really explain the fundamental core of what OO is and what its benefits are.

Principles are crucial but they are not the most important aspect of what OO actually is. What is really important is to understand in what grounds OO is built upon, or in other words, what are the foundations of OO programming.

The two most fundamental core concepts on which OO has been built upon in C# are this pointer and Dynamic Dispatch.

Obviously, there are principles like Encapsulation, Polymorphism, Abstraction, and Inheritance, but these are the consequence and not the generating force behind the OO paradigm in C#.

Question 3: What is the this Pointer?

The this pointer is silently passed with a call to an instance-level function, which then operates on an object (instance of a class).

Basically, this core mechanism makes it possible to bring operations close to data. It also eliminates the need to have global functions and it gives data structures the intrinsic ability to perform operations on its data.

So, having said this, if we now raise the following question:

Question 4: What is the OO fundamental idea using C# that allows a data structure to perform operations on its own data?

What would your answer be? Pretty obvious. The humble this pointer.

Notice that despite this being a mind-bending idea, we can already start to appreciate the bigger picture for which C# was designed.

The this pointer is basically a way for a data structure (object) to be able to access methods that allow itself to perform operations on its own data. It is a way to manage state within a data structure.

Now let’s talk a bit about the other core concept that takes this to the next level.

Question 5: What is Dynamic Dispatch?

Dynamic Dispatch becomes possible when each object carries data about its generating type, which is basically the object’s duty.

It is possible to achieve this when the type is able to keep track by using a virtual functions table, becoming the type’s duty. This allows an object to override some functions which have been inherited from its base type.

The bottom line is that when we place a call to a function, we don’t really know in an OO paradigm which function is really going to be executed.

In fact, it is the runtime’s duty to jump in when a call is placed on an object and determine which concrete function address to invoke, by looking at its generating type.

This constitutes the base of Polymorphism. If this sounds a bit intimidating, it will become clearer with an example going forward.

OO as a Mindset

One key aspect to understand is that it is possible to write OO code in a structured language like C, although the language itself was not designed with that paradigm in mind.

So it is not really the programming language that is object-oriented, but it’s more how we interact with it—how we use it.

It is true though those languages that are built from the ground up with OO fundamental core concepts and principles such as C#, make it easier for developers to implement code that is OO compliant, however, it is still largely known that many developers still use the language like they would use a procedural and structured language.

At the end of the day, OO is a shift in the thinking process on how developers write software. Some programming languages are better suited for this paradigm than others and C# is one of them.

Starting to think OO

So if C# is a language designed to be OO from the ground up—

Question 6: Why do we still see so much non-OO code written in C# today?

The problem basically resides in the fact that it takes a deep understanding of OO in order to actually start writing code that behaves that way.

In order to really start thinking about how to properly implement OO code, it is critically important to know what data goes together with which operations—this consists of defining objects, their data, and operations.

Also, it is important to recognize which operations requests are dispatched dynamically—this consists of applying virtual functions and method overrides by means of inheritance, which leads to Polymorphism.

At this point, everything else pretty much comes as a byproduct of the other two core concept just mentioned: defining data and operations together and recognizing which operations are dynamically dispatched.

These lead to objects being brought to life. This allows operations to be determined dynamically and behavior modified by substituting objects.

So in short, the this pointer which is part of every instance and dynamic dispatching, which makes it possible to substitute one function specification with another during runtime—without affecting the caller, are at the core of OO.

The rest of the known OO principles such as Inheritance and Abstract Types are simply syntactical sugar on top of these two fundamental concepts.

Question 7: How does OO simplify development?

The goal of any software is to be useful to its users. If you’ve been long enough in the software industry you know how much customer requirements can change throughout time and with every one of those changes, the code needs to be modified and re-checked.

This process can be a complicated endeavor depending on the scope of the requirements and changes associated with them.

Let’s take for instance the following example. The program below reverses a string. This was the initial user requirement. So given this requirement, one might be tempted to write this in C# using Visual Studio 2015 as follows.

Example Problem 1:

    using System;
    
    namespace TestApp
    {
        class Program
        {
            public static string ReverseString(string s)
            {
                string tmp = string.Empty;
    
                for (int i = s.Length - 1; i >= 0; i--)
                {
                    tmp += s[i].ToString();
                }
    
                return tmp;
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine(ReverseString("Pizza"));
                Console.Read();
            }
        }
    }

c# interview questions

Cool! That works. We’ve solved the user’s requirements in a simple way. However what happens if the requirements suddenly change and we are asked to filter out characters that are not letter or digits.

Easy right? We can solve this by simply adding a condition that evaluates if a character within the string is either a digit or a letter and if that is true, then the character can be appended to the temporary string that is returned by the function. Let’s have a look.

    using System;
    
    namespace TestApp
    {
        class Program
        {
            public static string ReverseString(string s)
            {
                string tmp = string.Empty;
    
                for (int i = s.Length - 1; i >= 0; i--)
                {
                    if (char.IsLetterOrDigit(s[i]))
                        tmp += s[i].ToString();
                }
    
                return tmp;
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine(ReverseString("P!zza"));
                Console.Read();
            }
        }
    }

If we execute this code with the string P!zza, we get the following result.

c# interview questions

Awesome, that also works. So that was easy to get resolved. But what happens if user requirements change again and they become a bit more complex. Say for instance that P1zza would be a valid string to reverse, but not P2zza or P3zza.

Although this is a hypothetical example, in real life user requirements are prone to change and this has a direct impact on the code we write.

At the moment, we are simply using C# to write procedural code. The class is simply a wrapper around the procedural code and nothing more.

We are not really doing any OO programming and definitely not using the full potential of C#.

Question 8: So how can we use the core concepts of OO in order to make this code easy to maintain and yet still flexible enough to cope with possibly ever-changing requirements?

In order to answer this question properly, we first need to understand what the problem is.

Basically, the issue with the way the current code has been written is that the decision of which characters should be reversed is static. The solution to the problem is to make that decision dynamically.

The static code runs into a fundamental problem every time a change needs to be done. That fundamental issue is that each change may break a feature that used to work fine. This is definitely not what any developer wants.

So in order to make the code less static, let’s consider this. What if we rewrite the code with a selector that is responsible for returning the characters that can be reversed?

Let’s have a look how this can be done.

Example Problem 2:

    using System;
    
    namespace TestApp
    {
        class Program
        {
            public static string ReverseString(string s, Selector sl)
            {
                string tmp = string.Empty;
    
                foreach (char c in sl.pick(s))
                {
                    tmp += s[i].ToString();
                }
    
                return tmp;
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine(ReverseString("P!zza"));
                Console.Read();
            }
        }
    }

In this example, we’ve removed the responsibility of determining which character in the string could be reversed from the ReverseString function to a Pick method available within a Selector instance that is passed to the calling function.

That’s definitely a step in the right direction as the responsibility should be contained within a class and not let the calling function (in this case ReverseString) to have to decide which characters to use.

Question 9: How to avoid the NULL trap?

In real life, null is nothing. However, in the programming world, null does represent the value of nothing. Basically, nothing is a value!

Still today, we see lots of code out there that contains many conditional statements that check if the value of a variable is null. This is a cause for concern in OO programming and here’s why.

Null is not an object. We might have a class, but when we have a variable with a null value we don’t have an object. Simply put, we cannot build OO code based on null references!

Therefore we need to avoid the null trap. Let’s examine the following code.

Example Problem 3:

    using System;
    
    namespace TestApp
    {
        class Program
        {
            public static string DisplayUpperStr(string s)
            {
                string upper = string.Empty;
    
                if (s == null)
                {
                    upper = null;
                }
                else
                {
                    upper = s.ToUpper();
                }
    
                return upper;
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine(DisplayUpperStr("to upper"));
                Console.Read();
            }
        }
    }

Syntactically, this code is perfectly fine and it produces the desired result, which is to convert to upper case a given string.

Even though this works fine, it is advisable from an OO perspective to consider constructing an object that represents nothing, rather than evaluating a condition that contains a null.

So in light of that, let’s modify the previous code as follows.

    using System;
    
    namespace TestApp
    {
        class Program
        {
            public static string DisplayUpperStr(PossibleString s)
            {
                string upper = s.ToPossiblyUpper();
    
                return upper;
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine(DisplayUpperStr("to upper"));
                Console.Read();
            }
        }
    }

Notice how all of a sudden, the DisplayUpperStr function became more readable, less cluttered and it no longer uses a conditional statement to check for a null value. Much cleaner and easier to maintain.

Furthermore, the responsibility of converting the string to the upper case has moved from the calling function to the PossibleString object, specifically by invoking its method ToPossiblyUpper.

Despite not having an implementation for a PossibleString class yet, we can already start to appreciate the benefit that the OO paradigm provides in this example.

This leads to a separation of concerns in the code, which eventually leads to Encapsulation.

So now that we’ve explored these concepts, let’s move to a state-related code base. So you might be asking yourself at this moment:

Well, it is a way to write code that basically replaces branching and conditional statements with functions and then some of those functions can be used to manage state within a class.

So, first things first and let’s start by turning conditions into functions. Let’s consider the following code.

Example Problem 4:

    using System;
    
    namespace TestApp
    {
        class Program
        {
            public static string DisplayUpperStr(PossibleString s)
            {
                string upper = s.ToPossiblyUpper();
    
                return upper;
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine(DisplayUpperStr("to upper"));
                Console.Read();
            }
        }
    }

In this example, we have defined a very basic class called Taxi.

Basically, this represents a private taxi company that only drives customers to their destination if the customer has booked a taxi through the company’s website beforehand. The taxi company doesn’t pick up any passenger from the street.

So considering this, there is a Pay method that has a guard clause. The clause is basically a conditional statement that checks if the taxi has been booked beforehand. If the taxi has not been booked, then no payment takes place (the PayToDriver method is not executed).

Although the Pay method has a guard clause and PayToDriver is only invoked when it really needs to be called, Pay is still responsible for checking if a taxi has been booked.

Ideally, what is required is to have this responsibility detached from the Pay method and have it as an Action that handles the booked state. So something like this:

    using System;
    
    namespace TestApp
    {
        public class Taxi
        {
            public void Pay()
            {
                this.ManageBooking();
                PayToDriver();
            }
        }
    }

This basically removes the condition from being the responsibility of the Pay method and delegates it to the ManageBooking method. This is what is called turning a condition into a function.

Now let’s take this a notch further and see how we can turn a function into a state. To do this, let’s redefine our function as an Action.

    using System;
    
    namespace TestApp
    {
        public class Taxi
        {
            public void Pay()
            {
                this.ManageBooking = this.StayVerified;
                PayToDriver();
            }
        }
    }

Notice that ManageBooking is no longer a method but instead an Action. By being an Action, the state (handled through the property StayVerified) can be directly assigned to the Action, delegate which is then fully responsible for handling state.

Notice how these small but crucial changes have been key in simplifying the code, making it more readable and at the same time, moving responsibility away from the calling class to the actual object that should ultimately be responsible for it.

As an exercise, you should now try to envision and create the implementation for the ManageBooking action. Notice that it should be an Action delegate. StayVerified can be implemented as a property.

Wrapping This Up

OO is a great programming paradigm and as a developer, having a good understanding of its fundamental core concepts will help you understand and successfully apply principles such as Polymorphism, Encapsulation, Inheritance, and Abstraction.

This leads to better code and one that is both agile and responsive to ever-changing user requirements.

We live in a world where the rate of change and complexity has dramatically increased over the last few years, however, the rate in which we produce maintainable software is not necessarily the same.

Therefore, knowing how the core concepts of C# in relation to OO can help in writing software that has a clear separation of concerns, greatly improves the chances of being able to adapt faster to an environment of continuous user requirement changes.

Overall, this should make you a stronger and better developer. Also, as the word nowadays is “agility”, being able to demonstrate how agility can be put forth as code, is a great way to make yourself noticeable to any recruiting party and help you shine during an interview.

Additional resource

I recommend a book called Object-Oriented Programming in C# Succinctly from Syncfusion which could be a great resource to explore this topic further. I hope this article has been an eye-opener and at the same time, enriching—and a lot of fun! Now go and get that job!

Other interview questions

React | Ruby on Rails | PHP | AngularJS | Java | iOS | Python | Javascript


Author’s Bio

c# interview questions in order to gather valuable insights on client patterns. He holds an M.S. in Computer Science. He enjoys soccer, running, traveling, and life hacking. You can reach him at edfreitas.me 

Discover and read more posts from Codementor Team
get started
Enjoy this post?

Leave a like and comment for Codementor

2
1
1Reply
PK
10 months ago

These are great theoretical C# questions, but I think every interviewer will also ask candidates to solve practical coding problems in C# to evaluate their ability. That’s why it’s good to practice those kinds of C# interview questions

Get curated posts in your inbox

Read more posts to become a better developer