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 crossplatform.
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 uent in the
language to land a job but also to have a good understanding of the
technology landscape that specically 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
ts 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 specic cases where it is the best
tool to carry out the task at hand.
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!
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 rst analyze what benets 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 benets 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 dening 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: dening 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 modied 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 specication
with another during runtime—without aecting 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 modied 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.
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 lter 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.
If we execute this code with the string P!zza, we get the following result.
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 denitely 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 exible enough to cope with possibly ever-changing requirements?
In order to answer this question properly, we rst 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 ne. This is denitely 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.
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 denitely 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:
Syntactically, this code is perfectly ne and it produces the desired result,
which is to convert to upper case a given string.
Even though this works ne, 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.
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,
specically by invoking its method ToPossiblyUpper .
Despite not having an implementation for a PossibleString class yet, we
can already start to appreciate the benet that the OO paradigm provides in
this example.
This leads to a separation of concerns in the code, which eventually leads to
Encapsulation.
Question 10: How to move to a State-related Codebase?
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:
Question 11: What is a state-related codebase?
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, rst things rst and let’s start by turning conditions into functions. Let’s
consider the following code.
In this example, we have dened 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:
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 redene our function as an Action.
Notice that ManageBooking is no longer a method but instead an Action. By
being an Action, the state (handled through the property StayVeried) 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 everchanging 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!
0 Comments