Tech Point Fundamentals

Sunday, July 17, 2022

C# Interview Questions and Answers - Part 09

C# Interview Questions and Answers - Part 09

csharp-interview-questions-and-answers-part1

Are you preparing for the C# Interview? If yes, then you are at the right place. This is the C# Interview Questions and Answers article series. Here we will see the Top 150+ C# Interview Questions with Answers. 

Please visit our YouTube Channel for Interviews and other videos by below link:



Please read the complete Design Patterns Interview Questions and Answers series here.


Introduction


This is the 9th part of this C# Interview Questions and Answers article series. Each part contains 10 C# Interview Questions with Answers. Please read all the C# Interview Questions list here.

I will highly recommend you to please read the previous parts over here before continuing the current part:





C# Interview Questions and Answers - Part 09


Q081. What is the difference between constant and readonly in C#?

Both const and readonly are used for defining constant in C#, but the purpose of both are different.

Const:

  1. A const is nothing but a variable of which the value is constant and known at compile time. So we cannot change the value of a const variable throughout the entire program.
  2. Constant fields are known as compile-time constants. They have a local scope
  3. It is mandatory to assign a value to the constant variable at the time of declaration itself otherwise it will give a compile-time error, that's why it is known as a compile-time constant.
  4. If you are using an expression for const initialization, the expression must be evaluated at compile time itself otherwise you will get a compile-time error.
  5. All the constants are static implicitly, so we cannot define a constant static explicitly.


  6. Constants can be marked as public, private, protected, internal, or protected internal access modifiers.
  7. A const variable cannot be passed as a ref or out parameter.
  8. A const variable can be referenced through the class name i.e. "ClassName.VariableName" as well because it is static internally.
  9. Any inbuilt data type can be used for constant declarations. You can also use reference types as well which must be initialized with the null value at the time of declaration. 
  10. A reference type object (with new keyword initialization) or nullable primitive types cannot be defined as constant.

const UserClass obj1 = null; //No Error, since it's evaluated a compile time
const UserClass obj2 = new UserClass(); //Error : since it's evaluated at run time



Readonly:

  1. Readonly fields are known as runtime constants. They have global scope i.e read-only fields can only be initialized at the class level.
  2. A readonly field can be initialized only either at the time of declaration itself or within the constructor of the same class. After that, the value for the readonly fields cannot be changed for that instance.
  3. Since a readonly field can be initialized in the constructor, it is also known as run-time constants. So if the readonly field is also initialized at the time of declaration, it will be overridden in the constructor, but after that, it cannot be changed further.
  4. The readonly keyword can be applied to both a value type and reference type i.e a readonly field can be defined for both value type and reference type data.
  5. A readonly field can be declared as static explicitly unlike a const field.
  6. A delegate and event cannot be readonly.
  7. You cannot create a readonly object or variable using the contextual var keyword. You must have to specify the data type explicitly.
  8. A readonly variable also cannot be passed as ref or out parameter like const.
  9. A readonly variable can be referenced through "ClassObject.ReadonlyVariableName". 








Const vs Readonly:

  • Both const and readonly are used to define the constants in C#. 
  • Both const and readonly are immutable, meaning the value cannot change throughout the life of the application. 

The difference between them lies in when the value of the variable is known throughout the lifecycle of the application. However, there are the following differences between them:

  1. For readonly fields, the latest value is known by the runtime while for the const, the value must be known by compile time.
  2. Const are compile-time constants while the readonly fields as run-time constants.
  3. Const has local scope while readonly has global scope.
  4. A const field cannot be specified as static explicitly, but a readonly can be marked as static explicitly.
  5. A const variables can be referenced through "ClassName.VariableName", while readonly can be referenced through "InstanceName.VariableName". 


  6. For the const keyword, the variable marked as such is placed by the compiler in the assembly metadata that defines the constant and metadata and embeds the value into the IL code after initialization. This means that there is no memory allocation for constants during runtime. On the other hand, under the hood, the readonly value is not a constant; it's stored in the loader heap, which is a memory type that cannot be allocated until the type is loaded. The readonly fields are stored in dynamic memory, the values are accessible only at runtime.
  7. These two keywords const and readonly use different binary versioning. When an expression references a specific constant, the compiler embeds the value at compile-time. This means if the value is used in a different assembly, the original needs to be updated and the value changed. The changes in the assembly are not reflected until it is recompiled. When an expression references a readonly field, the value is not obtained until runtime. Change in the value is reflected immediately, the assembly does not need to be recompiled.

Please watch the C# Const vs Readonly video here.



Q082. What is recursion? Which data structure is used by the recursion?

In computer science, recursion is a method of solving a problem where the solution depends on solutions to smaller instances of the same problem. A recursive function is a function that calls itself. 

A recursive algorithm is a special type of algorithm in which a method calls itself over and over again to solve a problem. Each successive call reduces the complexity of the problem and moves closer and closer to a solution until finally a solution is reached, the recursion stops, and the method can exit.  

Recursive algorithms are fairly easy to identify because the method name appears in the method body. Recursive algorithms are about breaking complex problems down into smaller more manageable problems. 



Every recursive method usually has two basic components:

1. Recursion Termination Condition: A Recursive method calls itself until the termination condition is being satisfied.

2. Recursion Parameter: The Recursive method has a parameter(s) that leads the recursion and calls itself with the new parameter values.

Recursion is a concept in which the method calls itself. Every recursive method needs to be terminated, therefore, we need to write a condition in which we check if the termination condition is satisfied. If we don’t do that, a recursive method will end up calling itself endlessly which causes a stack overflow exception. 

Since the C# compiler does not optimize the tail calls, it causes a StackOverflowException if the termination condition does not define properly.



Any recursive algorithm has two-phase, the winding phase and the unwinding phase.  Winding is simply the work that occurs before a recursive call, and unwinding is the work that occurs after the recursive call. 

public UInt64 Factorial(int number)
{
   return number == 0 ? 1 : number * Factorial(number - 1);
}

Recursive solution is a powerful and simple approach for complicated developments, but it can worsen performance because of using call stack again and again. The Recursive Methods solve problems and puzzles with brute force. Recursion can be used to implement certain forms of artificial intelligence as well. 



Types of Recursion: The placement of the recursive calls in a recursive algorithm determines the “type” of the recursive algorithm. 

Linear Recursion: Linear recursion is the simplest and most common form of recursion. In linear recursion, the recursive method must call itself, and it can only call itself recursively once per call.  For example Factorial(5) -> Factorial(5) -> Factorial(4) -> Factorial(3) -> Factorial(2) -> Factorial(1)

Tail Recursion: A recursive method is considered to be tail-recursive if nothing has to be done after the recursive call before the method exits. But remember, the physical placement of the recursion termination has nothing to do with it.  If the recursion occurs, then the method exits without doing anything else, then it is tail-recursive. 

Middle Recursion: In a middle recursion, there is some code both before and after the recursive call. Hence, the recursion occurs in the middle of the method.

Binary Recursion: In binary recursion, a recursive algorithm calls itself recursively twice per call.  It is a bit more complex than linear recursion because it branches out and creates various non-linear paths of execution. A recursive method implementing binary recursion must wait for both recursive calls to finish before it can be complete.  



Q083. What is a delegate in C#? Can you tell me some common delegates available in C#?

A delegate is a type-safe function pointer that can reference a method that has the same signature as that of the delegate. A delegate is a reference type variable that holds the reference to a method. Delegate is the reference type data type that defines the signature. The delegate type variable can refer to any method with the same signature as the delegate.

A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.

Delegates are used to pass methods as arguments to other methods. Event handlers are nothing more than methods that are invoked through delegates. This ability to refer to a method as a parameter makes delegates ideal for defining callback methods. 

Delegates are specially used for implementing events and call-back methods. All delegates are implicitly derived from the System.Delegate class.



public delegate int Calculate(int x, int y);
Calculate delegateInstance = new Calculate(CalculateMethod);  
delegateInstance();

Any method from any accessible class or struct that matches the delegate type can be assigned to the delegate. The method can be either static or an instance method. The delegate follows the variance feature as well. Please read more about Covariance vs Contravariance here for more details.

In the context of method overloading, the signature of a method does not include the return type value. But in the context of delegates, the signature does include the return type value. So a method must have the same return type as the delegate.

A delegate can be Single Cast or Multicast. Single cast delegates point to a single method at a time. When a delegate is wrapped with more than one method that is known as a multicast delegate.

FUNC, PREDICATE, and ACTION are some common inbuilt delegates in the .Net Framework. 



Q084. What is the use of FUNC, PREDICATE, and ACTION delegates in C#?

A delegate is a type-safe function pointer that can reference a method that has the same signature as that of the delegate. C# has built-in generic delegate types like Func, PREDICATE, and Action defined in the System namespace.

FUNC Delegate:

  1. Func is a generic delegate defined in the System namespace.
  2. The Func delegate takes zero, one or more input parameters along with one last OUT parameter that returns a value as an output. 
  3. A Func delegate type can include 0 to 16 input parameters of different types. However, it must include an out parameter for the result.

public delegate TResult Func<in T,out TResult>(T arg);



Func Delegate follows the variance feature. It has both covariant return types and contravariant parameter types. 

  • Since the input parameter (T) is contravariant, you can use either the type you specified or any type that is less derived. 
  • Since the output parameter (TResult) is covariant, you can use either the type you specified or any type that is more derived here.

We can use this delegate to represent a method that can be passed as a parameter without explicitly declaring a custom delegate. We can also assign an anonymous method to the Func delegate by using the delegate keyword.

Func<string, string> convert = delegate(string s) { return s.ToUpper();};

A Func delegate can also be used with a lambda expression as well.

Func<string, string> convert = str => str.ToUpper(); // OR
Func<string, string> convert = () => str.ToUpper();



PREDICATE Delegate:

  1. A Predicate is a delegate like Func and Action delegates which returns a boolean true or false as a result. 
  2. It represents a method containing a set of criteria and checks whether the passed parameter meets those criteria. 
  3. A predicate delegate method must take one input parameter and return a boolean value.
  4. The Predicate delegate is defined in the System namespace as follows. The input parameter (T) is contravariant here as well like Func delegate.

public delegate bool Predicate<in T>(T obj);

Same as other delegate types, Predicate can also be used with any method, anonymous method, or lambda expression. But typically, the Predicate<T> delegate is represented by a lambda expression.

This delegate is used by several methods of the Array and List<T> classes to search for elements in the collection. 



ACTION Delegate:

  1. An Action type delegate is the same as a Func delegate except that the Action delegate doesn't return a value
  2. It is also defined in the System namespace. So an Action delegate can be used with a method that has a void return type.

public delegate void Action<in T>(T obj);

The input parameter is contravariant for the Action Delegate as well. An Action delegate can take up to 16 input parameters of different types.

An Anonymous method can also be assigned to an Action delegate. A Lambda expression also can be used with an Action delegate.

Please read the CoVariance vs ContraVariance article here for more details.



Q085. What are the generics in C#, and why they are required? How can you define a generic class and methods in C#?

In C# generic means a general form, not specific; means not specific to a particular data type.  Generics are the most powerful feature of C#. Generics allow you to define type-safe data structures, without committing to actual data types. Generics are generally used to create generic collections in C#. In C# Generics are introduced as part of C# 2.0

Generics introduces the concept of type parameters to .NET, which makes it possible to design classes and methods that defer the specification of one or more types until the class or method is declared and instantiated by client code.

Generics are used to decouple the data type from method, class, or interface. Generic is a concept that allows us to define classes and methods with a placeholder. C# compiler replaces these placeholders with the specified type at compile time. Generics in C# allow us to define classes and methods which are decoupled from the data type. 



C# allows you to define generic classes, interfaces, abstract classes, fields, methods, static methods, properties, events, delegates, and operators using the type parameter and without the specific data type. Generic classes and methods combine reusability, type safety, and efficiency in a way that their non-generic counterparts cannot.

A generic type is declared by specifying a type parameter in angle brackets after a type name, e.g. TypeName<T> where T is a type parameter. It is not required to use T as a type parameter. You can give any name to a type parameter. Generally, T is used when there is only one type parameter. 

A type parameter is a placeholder for a particular type specified when creating an instance of the generic type. We can also define multiple type parameters separated by a comma.

The System.Collections.Generic namespace contains several generic-based collection classes.  Information on the types that are used in a generic data type may be obtained at run-time by using reflection.








Advantage of Generics:

  1. Generics allows us to define classes and methods which are decoupled from the data type, so it increases the reusability of the code.
  2. Generics are type-safe. You get compile-time errors if you try to use a different data type than the one specified in the definition.
  3. Generic has a performance advantage because it removes the possibilities of boxing and unboxing.
  4. Generics have removed the limitation of ArrayList defined the System.Collections namespace by introducing generic collections in System.Collections.Generic namespace.



Generic Class:

  1. Generic classes are defined using a type parameter in angle brackets after the class name. 
  2. A generic class can be a base class for other generic or non-generic classes or abstract classes.
  3. A generic class can be derived from other generic or non-generic interfaces, classes, or abstract classes.
  4. A generic class increases the reusability. However, too much generalization makes code difficult to understand and maintain.
  5. You can create an instance of generic classes by specifying an actual type in angle brackets.

public class GenericList<T>
{
    public void Add(T input) { }
}



Generic Method:

  1. The generic parameter type can be used with multiple parameters with or without non-generic parameters and return type.
  2. A non-generic class can include generic methods by specifying a type parameter in angle brackets with the method name.

public void Message<T>(T msg)
{
Console.WriteLine(msg);
}



Q086. What is the difference between System.Collections and System.Collections.Generic namespaces?

C# includes specialized classes that store series of values or objects called collections. There are two types of collections in C#: Non-Generic collections and Generic collections.

The System.Collections namespace contains the non-generic collection types and System.Collections.Generic namespace includes generic collection types. 

System.Collections namespace contains interfaces and classes that define various collections of objects, such as ArrayList, Hashtable, Queue, Stack, SortedList, ICollection, IDictionary, IEnumerable, IEnumerator, IList, IEqualityComparer, etc.



System.Collections.Generic namespace contains interfaces and classes that define generic collections, which allow users to create strongly typed collections that provide better type safety and performance than non-generic strongly typed collections.

System.Collections.Generic  contains: Comparer<T>, Dictionary<TKey,TValue>, HashSet<T>, LinkedList<T>, List<T>, Queue<T>, Stack<T>, SortedList<TKey,TValue>, SortedDictionary<TKey,TValue>, ICollection<T>, IEnumerable<T>, IEnumerator<T>, IList<T>, IReadOnlySet<T> etc.

Generic collections are always recommended because they perform faster than non-generic collections and also minimize exceptions by giving compile-time errors.



Q087. What is the difference between an Array and ArrayList in C#?

An Array is a fixed-length sequential collection of similar data types items (homogeneous collections) that can be accessed as per the “index”. It is the simplest type of data structure in which the elements get stored in a contiguous memory location. In an array, the index starts with zero.

The ArrayList is a collection of objects of the same or different data types. The size of an ArrayList can be dynamically increased or decreased as per the requirement. It works like an array but unlike an array in ArrayList, items can be dynamically allocated or deallocated.



Array vs ArrayList:

  1. An Array is defined in the System namespace while ArrayList is defined in System.Collection namespace.
  2. An Array is strongly-typed so we can store only the same type of data. While ArrayList is a non-generic collection type and we can store any type of data in ArrayList.
  3. We do not need to cast elements of an array while retrieving because it is strongly typed and stores a specific type of item only. On the other hand, the items of ArrayList need to be cast to an appropriate data type while retrieving.
  4. An array can store a fixed number of elements but ArrayList is dynamic in terms of capacity hence it is variable in size.
  5. An Array cannot accept a null value while ArrayList can contain a null value because internally it uses Object as the data type.
  6. Array provides better performance than ArrayList because the array does not cause boxing and unboxing while ArrayList performs boxing and unboxing.

Please watch the Boxing vs Unboxing video here for more details.








Q088. What’s the difference between the Array.CopyTo and Array.Clone?

An array in C# is a collection of similar data items accessed using a numeral index. But remember that the array always starts with index 0, not from 1. In our daily task on array there may be situations where we want to work with a new array but copy items from an existing array to it, or copy items from one array into another array. 

For that array provides multiple ways i.e CopyTo, ConstrainedCopy, and Clone. But all do a shallow copy not a deep copy. Shallow copying is creating a new object and then copying the non-static fields of the current object to the new object. If the field is a value type, a bit-by-bit copy of the field is performed. A shallow copy of an object is a new object whose instance variables are identical to the old object.

The Clone() method returns a new array object (a shallow copy) containing all the elements in the original array. While the CopyTo() method copies the elements into another existing array. But both perform a shallow copy only.



Array.CopyTo:

  1. The ArrayCopy() is a static helper method. It copies elements from one array to another. 
  2. The destination array has to be already created with the right dimension. 
  3. The Array.CopyTo copies all the elements of the current array to the specified destination array.
  4. This CopyTo method should be called from the source array and it takes two parameters. The first is the array you want to copy to, and the second parameter tells it what index of the destination array it should start copying into. 
  5. Array.ConstrainedCopy is similar to Array.CopyTo. The only difference is that Array.ConstrainedCopy guarantees that all changes are undone if the copy operation does not succeed completely because of some exceptions.

var source = new[] { 1, 8, 9 };
var target = new string[4];
source.CopyTo(target, 1);



Array.Clone:

  1. This method also performs a shallow copy of the array elements. The Clone() method implements the ICloneable interface. It creates a new instance of the array holding the same elements but returns the object you have to cast.
  2. The Array.Clone() method returns a new array object containing all the elements in the original array. 
  3. This method creates a copy of an array as an object, therefore needs to be cast to the actual array type before it can be used to do very much. The clone is of the same type as the original array.
  4. If the array contains reference types data, only those references are copied, but the actual objects that the references refer to are not. 

int[] numberArray = {10,15,18,38,23};
int[] clonedNumberArray = (int[])numberArray .Clone();



Note:

If the elements of the array are of reference types, then both Clone and CopyTo will be made up to the first (top) level only (i.e shallow copy) i.e the reference is copied but the referred object is not. But the lower-level items don't get copied. A shallow copy of an object is a new object whose instance variables are identical to the old object.

If we need a copy of the lower level also, we have to do it explicitly.  That's why after the Cloning or Copying of reference type elements, each element in the Cloned or Copied array refers to the same memory location as referred by the corresponding element in the original array. So no separate instance is created for the lower level. 



Q089. What is an indexer in C#? What is the difference between indexer and property?

Indexers allow instances of a class or struct to be indexed just like arrays. A C# indexer is a class property that allows you to access a member variable of a class or struct using the features of an array. An Indexer is the same as a property that has a parameter so you can think of an indexer as parameterized property.

The indexed value can be set or retrieved without explicitly specifying a type or instance member. Indexers resemble properties except that their accessors take parameters.



  1. Indexers enable objects to be indexed in a similar manner to arrays. Indexers are always used on collections or groups of elements.
  2. There should be at least one parameter specified in the indexer.
  3. A get accessor returns a value while a set accessor assigns a value and both use the [ ] operator to get and set the value.
  4. The "value" keyword is used to define the value being assigned by the set accessor.
  5. Both structures and classes can define indexers. But Static class can not define an indexer.
  6. A "this" keyword is used to define the indexer.
  7. A static class cannot have an indexer because the "this" keyword is not supported in static classes. 
  8. Since the indexer is an instance member it cannot be static.
  9. A REF and OUT parameter modifiers are not permitted in the indexer. Please watch the REF vs OUT video here for more details. 
  10. Indexers do not have to be indexed by an integer value; it is up to you how to define the specific look-up mechanism.
  11. Indexers can also be overloaded same as methods, constructors, and operators.
  12. Indexers can have more than one formal parameter, for example, when accessing a two-dimensional array.
  13. Indexer is identified by its signature that's why indexers are accessed using indexes.



It is common for an indexer's get or set accessor to consist of a single statement that either returns or sets a value. 

class UserCollection<T> { // Declare an array to store the data elements. private T[] arr = new T[100]; // Define the indexer to allow client code to use [] notation. public T this[int i] { get { return arr[i]; } set { arr[i] = value; } } }



Starting with C# 6, a read-only indexer can be implemented as an expression-bodied member. Note that => introduces the expression body and that the get keyword is not used. 

Starting with C# 7.0, both the get and set accessor can be implemented as expression-bodied members. In this case, both get and set keywords must be used. 

class UserCollection<T> { // Declare an array to store the data elements. private T[] arr = new T[100]; // Define the indexer to allow client code to use [] notation. public T this[int i] { get => arr[i]; set => arr[i] = value; } }



Indexer vs Property:

  1. Indexers are created with this keyword while properties do not require "this" keyword.
  2. Indexer always requires a parameter for accessing(both get and set) while property does not require any parameter.
  3. Indexers are instance members so they cannot be static but properties can be static.
  4. A static class cannot have an indexer but properties can be defined in a static class.
  5. Indexers are identified by their signatures while properties are identified by their names.
  6. Indexers are accessed using indexes while properties are accessed by their names.
  7. Indexers can be overloaded but property cannot be overloaded. Please read the overloading article here for more details. 

Please read more about indexer overloading here.









Q090. What is the difference between debug and release mode?

Visual Studio projects have separate release and debug configurations for your project. You can build the debug version for debugging and the release version for the final release distribution. You can change the build configuration from the Build menu, from the toolbar, or from the project's property pages.
 
In debug configuration, your program compiles with full symbolic debug information and no optimization. Optimization complicates debugging because the relationship between source code and generated instructions is more complex. The release configuration of your program has no symbolic debug information and is fully optimized.
 
For managed code and C++ code, debug information is generated in .pdb files, depending on the compiler options that are used. Creating .pdb files can be useful if you later have to debug your release version.



There is no difference in the functionality of a debug DLL and a release DLL. usually, when we compile code in debug mode, we have a corresponding .pdb (program database) file. This .pdb file contains information that enables the debugger to map the generated IL (intermediate language) to the source code line number. It also contains the names of local variables in the source code.

The compiler emits an instance of the System.Diagnostics.DebuggableAttribute. In the debug version, the IsJitOptimizerEnabled property is True, in the release version it is False.

You can see this attribute in the assembly manifest with ildasm.exe. The JIT compiler uses this attribute to disable optimizations that would make debugging difficult. The ones that move code around like loop-invariant hoisting. In selected cases, this can make a big difference in performance. Not usually though.








Debug mode is used when we are developing the application and release mode is used when we are going to production or deploying the application to the server.

The debug mode code is not optimized while the release mode code is optimized.
In debug mode, the application performance will be slightly slow while in release mode the application will be faster.

In the debug mode the debug symbols (#IF DEBUG or [Conditional("DEBUG")]) will be executed which are ignored in the release mode.

The debug mode dll and exe generate complete exception stack trace information while the release build does not.

Please watch the C# Debug vs Release Mode video here

To Be Continued Part-10...


Recommended Articles






Thanks for visiting this page. Please follow and join us on LinkedIn, Facebook, Telegram, Quora, YouTube, Twitter, Pinterest, Tumbler, and VK for regular updates.


No comments:

Post a Comment

Please do not enter any HTML. JavaScript or spam link in the comment box.